繁体   English   中英

通用接口属性在实现中是虚拟的

[英]Generic interface property is virtual in implementation

我有一个名为“ Entity”的模型,该模型实现了“ IEntity”接口,如下所示(简化):

public interface IEntity<T> where T : IComparable
{
    T Id { get; set; }
}

public class Entity: IEntity<Guid>
{
    public Guid Id { get; set; }
    public Guid LayoutId { get; set; }
    public virtual Layout Layout {get; set;}
}

我想克隆此“实体”模型的对象,同时忽略以下虚拟属性:

public static class CloneHelper
{
    public static T CloneNonVirtual<T>(this T source) where T : class
    {
        var cloneObj = Activator.CreateInstance<T>();
        foreach (var prop in source.GetType().GetProperties().Where(w => w.CanWrite && !w.GetAccessors().Any(x => x.IsVirtual)))
        {
            var cloneObjProp = cloneObj.GetType().GetProperty(prop.Name);
            cloneObjProp.SetValue(cloneObj, prop.GetValue(source));
        }
        return cloneObj;
    }
}

在这里,问题在于LayoutId的访问器不是虚拟的,而Id的访问器是虚拟的! 请同时查看两个QuickWatch窗口: ID的访问者是虚拟的LayoutId的访问器不是虚拟的

为什么会发生这种情况? 这是因为Id是通用接口“ IEntity”的实现属性吗? 如果是这样,并且这是预期的行为,为什么?

谢谢,

功力

简短的版本是这就是CLR的工作方式。 请注意MethodBase文档中的这段文字:

公共语言运行时要求所有实现接口成员的方法都必须标记为虚拟

换句话说:之所以这样,是因为CLR表示必须采用这种方式。

更一般而言,当在编译时不知道要分派的方法时,将使用虚拟方法。 对于未声明为virtual方法且未实现某些接口成员的方法,C#编译器可以在编译时确定要调用的方法,并可以在IL中生成特定的,效率更高的方法调用类型,以用于这个目的。

对于其他方法,可能需要从实际实现类型未知的上下文中调用它们,因此必须通过方法表( “ vtable” )路由对此类方法的调用。 这既适用于实际的virtual方法(即,这样声明的方法),也适用于实现接口成员的方法,因为可以从(通常是)从上下文中调用后一种方法,在该上下文中,所有已知的只是接口类型,而不是实际的实现类型。 通过使用vtable,调用者只需知道vtable的位置和格式,而不是实现类型即可。

因为真正的virtual方法和接口成员的功能基本相同,所以在底层CLR实现级别上,它们都被视为相同。 (通常…在文档中也要注意,接口实现成员也被标记为final ,指示它们不能被覆盖)。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM