对某些C#代码有一个奇怪的问题 - 当没有明确标记时,属性的Getter方法显示为虚拟.
该问题在此类上显示DbKey属性(代码完整):
public class ProcessingContextKey : BusinessEntityKey, IProcessingContextKey { public ProcessingContextKey() { // Nothing } public ProcessingContextKey(int dbKey) { this.mDbKey = dbKey; } public int DbKey { get { return this.mDbKey; } set { this.mDbKey = value; } } private int mDbKey; public override Type GetEntityType() { return typeof(IProcessingContextEntity); } }
当我使用反射来检查DbKey属性时,我得到以下(意外)结果:
Type t = typeof(ProcessingContextKey); PropertyInfo p = t.GetProperty("DbKey"); bool virtualGetter = p.GetGetMethod(true).IsVirtual; // True! bool virtualSetter = p.GetSetMethod(true).IsVirtual; // False
为什么virtualGetter设置为True?鉴于该属性既不是抽象的也不是虚拟的,我期望是假的.
为了完整性 - 以及它们相关的远程可能性,这里是BusinessEntityKey,IProcessingContextKey和IBusinessEntityKey的声明:
public abstract class BusinessEntityKey : IBusinessEntityKey { public abstract Type GetEntityType(); } public interface IProcessingContextKey : IBusinessEntityKey { int DbKey { get; } } public interface IBusinessEntityKey { Type GetEntityType(); }
在此先感谢您的帮助.
澄清 - 为什么这对我来说很重要?
我们正在使用NHibernate,并将延迟加载的一些问题追溯到只有一半可覆盖的属性 - 虚拟getter但私有setter.在解决这些问题之后,我们添加了一个单元测试来捕获可能发生这种情况的任何其他地方:
public void RequirePropertiesToBeCompletelyVirtualOrNot() { var properties = typeof(FsisBusinessEntity).Assembly .GetExportedTypes() .Where(type => type.IsClass) .SelectMany( type => type.GetProperties( BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)) .Where(property => property.CanRead && property.CanWrite) .Where(property => property.GetGetMethod(true).IsVirtual != property.GetSetMethod(true).IsVirtual); Assert.That( properties.Count(), Is.EqualTo(0), properties.Aggregate( "Found : ", (m, p) => m + string.Format("{0}.{1}; ", p.DeclaringType.Name, p.Name))); }
这个单元测试在上面提到的DbKey属性上失败了,我不明白为什么.
它是虚拟的,因为它实现了一个接口方法.就CLR而言,接口实现方法总是虚拟的.
DbKey属性getter在IL中是虚拟的,因为它位于接口中.setter不是虚拟的,因为它不是接口的一部分,而是具体类的一部分.
ECMA-335:公共语言基础设施第8.9.4节注意到:
接口可以有静态或虚方法,但不能有实例方法.
因此,在派生类中实现时,接口定义的getter将标记为虚拟.
链接到解释实现接口的属性的文档始终标记为虚拟.要查看它是否真的是虚拟的(因为它实现了一个接口),您还需要检查它是否为IsFinal.