2010-04-26 20 views
18

Declarar una propiedad en una clase derivada que coincide con el nombre de una propiedad en la clase base "lo oculta" (a menos que lo anule con la palabra clave override). Tanto las propiedades de clase base como las derivadas serán devueltas por Type.GetProperties() si sus tipos no coinciden. Sin embargo, si sus tipos coinciden con, sorprendentemente solo se devuelve la propiedad de la clase derivada. Por ejemplo:Ocultar y reflejar propiedades (C#)

class A 
{ 
    protected double p; 
    public int P { get { return (int)p; } set { p = value; } } 
} 
class B : A 
{ 
    public new int P { get { return (int)p; } set { p = value; } } 
} 
class C : B 
{ 
    public new float P { get { return (float)p; } set { p = value; } } 
} 

Calling typeof(C).GetProperties() sólo devolverá p.e y C. P. ¿Es posible llamar al GetProperties() de una manera que devuelva los tres? Es casi seguro que hay una manera de hacerlo al atravesar la jerarquía de herencia, pero ¿hay una solución más limpia?

+0

¿Por qué quieres tener una jerarquía tal clase? – driis

+1

@driis: Este es solo un ejemplo trivial para ilustrar. Pero, por el bien del argumento, supongamos que esta jerarquía de clase está escrita por alguien que no sea yo, pero aún necesito encontrar todas sus propiedades públicas, incluso las ocultas. –

+0

Como no hay forma de que el uso de la clase derivada pueda acceder a la propiedad oculta, supongo que efectivamente no tiene esa propiedad para Reflection. Considérese afortunado, VB solo muestra C.P al usar Sombras. – Wilhelm

Respuesta

5

GetProperties se define como todas las propiedades públicas del tipo.

Usted podría conseguir su get y métodos establecidos usando:

typeof(C).GetMethods() 
     .Where(m => m.Name.StartsWith("set_") || m.Name.StartsWith("get_")) 

Aunque esto parece una mala idea, en lugar de ir abajo en la jerarquía de herencia para obtener las propiedades.

+1

Entonces tendrías el mismo problema con el método get_P que oculta el del padre, creo. – driis

+1

@Yuriy: typeof (C) .GetMethods(). Donde @driis: No, parece que funciona correctamente. –

+0

Acabo de intentarlo. Obtengo todos 6. –

5

No creo que sea posible sin atravesar la jerarquía de herencia. No tiene por qué ser demasiado código, sin embargo:

public static IEnumerable<PropertyInfo> GetAllProperties(Type t) 
    { 
     while (t != typeof(object)) 
     { 
      foreach (var prop in t.GetProperties(BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.Instance)) 
       yield return prop; 
      t = t.BaseType; 
     } 
    } 

Por supuesto, si usted sabe un BaseType común se puede parar en lugar de objeto, que será más eficiente. También; llevará algún tiempo hacer la reflexión, así que guarde el resultado en caché. Después de todo, la información del tipo no cambiará durante la ejecución.

+0

¿Esto no dará lugar a propiedades anuladas varias veces? –

+0

No, porque dijo BindingFlags.DeclaredOnly. –

+0

El problema aquí es que si volvemos a escribir nuestra jerarquía de clases para que B.P prevalezca sobre A.P, todavía obtenemos tres propiedades, aunque ahora un objeto de tipo C solo tiene dos. –

2

A través de la reflexión, la nueva palabra clave solo oculta la propiedad heredada si la firma coincide. Supongo que la reflexión coincide con las firmas en los accesadores de propiedades (get_ & set_). Es por eso que GetProperties() devuelve B.P y C.P cuando el tipo de devolución difiere.

Recientemente descubrí Fasteflect que proporciona mecanismos de reflexión avanzados.

Revisé y Fasteflect type.Properties devuelve todo el árbol de miembros ocultos (P). Creo que la API consideran copias de los miembros (virtual/override) y miembros ocultos (nuevo) diferente que es una buena cosa para su 'problema';)

Mi prueba con fasterflect:

class Class1 
{ 
    public object field1 = null; 

    public virtual object Property1 { get; set; } 

    public object Property2 { get; set; } 

    public string Property3 { get; set; } 
} 

class Class2 : Class1 
{ 
    public new object field1 = null; 

    public override object Property1 { get; set; } 

    public new string Property3 { get; set; } 
} 

class Class3 : Class2 
{ 
    public new string Property3 { get; set; } 
} 

elementos de soporte de filtro pero devuelve todos los miembros ocultos:

typeof(Class3).Properties(Flags.ExcludeBackingMembers | Flags.Public | Flags.Instance) 
  • typeof (clase 3) .properties (Flags.ExcludeBackingMembers | Flags.Public | Flags.Instance) Count = 5 System.Collections.Generic.IList
    • [0] {System.String Property3} System.Reflection.PropertyInfo
    • [1] {System.Object Property1} System.Reflection.PropertyInfo
    • [2] {System.String Property3} System.Reflection.PropertyInfo
    • [3] {System.Object Property2} System.Reflection.PropertyInfo
    • [4] {System.String Property3} System.Reflection.PropertyInfo
+0

http://msdn.microsoft.com/en-us/library/51y09td4%28VS.71%29.aspx#vclrfnew_newmodifier: Una constante, campo, propiedad o tipo introducido en una clase o estructura oculta a todos los miembros de la clase base con el mismo nombre. –

+0

No a través de la reflexión. Como las propiedades son accesadores, creo que la reflexión coincide con las firmas en los métodos de acceso (get_ & set_). – JoeBilly

+0

Después de algunas pruebas e inspecciones de Fasterflect, puedo decir con seguridad que su respuesta a este problema es totalmente equivalente a la de driis. Su solución recursiva para encontrar miembros ocultos es incapaz de excluir propiedades virtuales que han sido anuladas. (De hecho, establecer el marcador ExcludeBackingMembers de alguna manera excluye las tres propiedades en ambos casos). Sin embargo, gracias por el enlace. –