2008-11-26 75 views
11

对于某些C#代码有一个奇怪的问题 - 属性的Getter方法在未明确标记时显示为虚拟。为什么这个属性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?我预计假的,因为该属性既不是抽象也不是虚拟

为了完整性 - 和远程possibilty它们是相关的,这里有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但私人二传手。解决这些后,我们增加了一个单元测试来捕捉任何其他地方可能出现这种情况:

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财产,我不明白为什么。

+0

旁边的问题,为什么这是一个问题? – user7116 2008-11-26 20:48:43

回答

21

它是虚拟的,因为它实现了一种接口方法。就CLR而言,接口实现方法始终是虚拟的。

6

的DBKEY属性getter是在IL虚拟因为它是在一个接口。 setter不是虚拟的,因为它不是界面的一部分,而是具体类的一部分。

ECMA-335: Common Language Infrastructure第8.9.4注意到:

接口可以有静态的或虚拟的方法,但不得有实例方法。

因此,在派生类中实现时,由接口定义的getter将标记为虚拟。

5

Link到解释说,实现接口属性始终标示虚拟的文档。要看它是否真的是虚拟的(因为它实现了一个接口),你还需要检查它是否是最终的。