[英]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是通用接口“ IEntity”的实现属性吗? 如果是这样,并且这是预期的行为,为什么?
谢谢,
功力
简短的版本是这就是CLR的工作方式。 请注意MethodBase
文档中的这段文字:
公共语言运行时要求所有实现接口成员的方法都必须标记为虚拟
换句话说:之所以这样,是因为CLR表示必须采用这种方式。
更一般而言,当在编译时不知道要分派的方法时,将使用虚拟方法。 对于未声明为virtual
方法且未实现某些接口成员的方法,C#编译器可以在编译时确定要调用的方法,并可以在IL中生成特定的,效率更高的方法调用类型,以用于这个目的。
对于其他方法,可能需要从实际实现类型未知的上下文中调用它们,因此必须通过方法表( “ vtable” )路由对此类方法的调用。 这既适用于实际的virtual
方法(即,这样声明的方法),也适用于实现接口成员的方法,因为可以从(通常是)从上下文中调用后一种方法,在该上下文中,所有已知的只是接口类型,而不是实际的实现类型。 通过使用vtable,调用者只需知道vtable的位置和格式,而不是实现类型即可。
因为真正的virtual
方法和接口成员的功能基本相同,所以在底层CLR实现级别上,它们都被视为相同。 (通常…在文档中也要注意,接口实现成员也被标记为final
,指示它们不能被覆盖)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.