2008-11-26 20 views
11

Tiene un problema extraño con algunos códigos C#: el método Getter para una propiedad se muestra como virtual cuando no está marcado explícitamente.¿Por qué esta propiedad Getter es virtual?

Los problemas expuestos con la propiedad DbKey en esta clase (código en su totalidad):

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); 
    } 
} 

Cuando uso reflexión para inspeccionar la propiedad DbKey, consigo el (inesperado) siguiente resultado:

Type t = typeof(ProcessingContextKey); 
PropertyInfo p = t.GetProperty("DbKey"); 
bool virtualGetter = p.GetGetMethod(true).IsVirtual; // True! 
bool virtualSetter = p.GetSetMethod(true).IsVirtual; // False 

¿Por qué virtualGetter se establece en True? Esperaba que fuera falso, dado que la propiedad no es abstracta ni virtual.

Para completar - y por la posibilidad remota de que son relevantes, aquí están las declaraciones de BusinessEntityKey, IProcessingContextKey y IBusinessEntityKey:

public abstract class BusinessEntityKey : IBusinessEntityKey 
{ 
    public abstract Type GetEntityType(); 
} 

public interface IProcessingContextKey : IBusinessEntityKey 
{ 
    int DbKey { get; } 
} 

public interface IBusinessEntityKey 
{ 
    Type GetEntityType(); 
} 

gracias de antemano por su ayuda.

aclaración - ¿por qué me importa esto?

Estamos usando NHibernate y hemos rastreado algunos problemas con la carga diferida de propiedades que eran solo medio invalidables: virtual getter pero private setter. Después de fijar estas arriba, hemos añadido una prueba unitaria para atrapar cualquier otro lugar donde esto puede suceder:

prueba
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))); 
} 

Esta unidad estaba fallando en la propiedad DbKey mencionado anteriormente, y que no entendía por qué.

+0

Pregunta al lado, ¿por qué es esto un problema? – user7116

Respuesta

21

Es virtual porque implementa un método de interfaz. Los métodos de implementación de la interfaz son siempre virtuales en lo que respecta al CLR.

6

El captador de propiedades DbKey es virtual en la IL porque está en una interfaz. El colocador no es virtual porque no es parte de la interfaz sino parte de la clase concreta.

ECMA-335: Common Language Infrastructure Sección 8.9.4 señala que:

Las interfaces pueden tener métodos estáticos o virtuales, pero no tendrán métodos de instancia.

Por lo tanto, el getter definido por su interfaz se marcará virtual cuando se implemente en una clase derivada.

5

Link a la documentación que explica que las propiedades que implementan interfaces siempre se marcan como virtuales. Para ver si es realmente virtual (ya que implementa una interfaz) también deberá verificar si es Final.

Cuestiones relacionadas