2008-11-10 21 views
19

Más específicamente, si tengo:¿Cómo uso la reflexión para obtener propiedades que implementen explícitamente una interfaz?

public class TempClass : TempInterface 
{ 

    int TempInterface.TempProperty 
    { 
     get; 
     set; 
    } 
    int TempInterface.TempProperty2 
    { 
     get; 
     set; 
    } 

    public int TempProperty 
    { 
     get; 
     set; 
    } 
} 

public interface TempInterface 
{ 
    int TempProperty 
    { 
     get; 
     set; 
    } 
    int TempProperty2 
    { 
     get; 
     set; 
    } 
} 

¿Cómo se utiliza la reflexión para obtener todas las propiedades de aplicación para propertyInfos explícitamente TempInterface?

Gracias.

+0

¿Puede aclarar exactamente lo que está buscando? ¿Simplemente desea una lista de todas las propiedades explícitamente implementadas por TempClass?¿O solo quieres las propiedades de TempInterface? etc. –

+0

Quiero una lista de todas las propiedades explícitamente implementadas por TempClass –

Respuesta

1

tuve que modificar la respuesta de Jacob Carpenter, pero funciona muy bien. Nobugz también funciona, pero Jacobs es más compacto.

var explicitProperties = 
from method in typeof(TempClass).GetMethods(BindingFlags.NonPublic | BindingFlags.Instance) 
where method.IsFinal && method.IsPrivate 
select method; 
+0

Tu respuesta es conseguir métodos, Jacob está obteniendo las propiedades como lo hiciste originalmente en la pregunta. – nawfal

1

Es demasiado complejo. Debe reflexionar sobre los métodos/propiedades del tipo de interfaz, ver si existen en su tipo de clase y compararlos para ver si son los "mismos" cuando existen.

Si hay algo en la interfaz pero no del tipo que está probando, es una implementación explícita. Si está en ambos, pero diferente entre los dos, es una interfaz explícita.

+0

Si una clase implementa una interfaz, implementa todas las propiedades y métodos en esa interfaz. Entonces no tiene que examinar a los miembros de la clase, solo tiene que examinar a los miembros de la interfaz. –

+0

Tiene que comparar los miembros de la interfaz con los miembros de la clase para averiguar si el miembro está * explícitamente * implementado o no. – MrKurt

0

código de Jacob le falta un filtro:

 var props = typeof(TempClass).GetInterfaces().Where(i => i.Name=="TempInterface").SelectMany(i => i.GetProperties()); 
     foreach (var prop in props) 
      Console.WriteLine(prop); 
+0

Si solo desea las propiedades de interfaz de TempInterfaces, ¿por qué no comenzar con typeof (TempInterface)? –

+1

Porque eso requeriría que fuera más inteligente que yo. –

4

La propiedad getter y setter de una propiedad de interfaz implementada de manera explícita tiene un atributo inusual. Su propiedad IsFinal es Verdadera, incluso cuando no es miembro de una clase sellada. Prueba este código para verificar mi afirmación:

foreach (AssemblyName name in Assembly.GetEntryAssembly().GetReferencedAssemblies()) { 
    Assembly asm = Assembly.Load(name); 
    foreach (Type t in asm.GetTypes()) { 
     if (t.IsAbstract) continue; 
     foreach (MethodInfo mi in t.GetMethods(BindingFlags.NonPublic | BindingFlags.Instance)) { 
     int dot = mi.Name.LastIndexOf('.'); 
     string s = mi.Name.Substring(dot + 1); 
     if (!s.StartsWith("get_") && !s.StartsWith("set_")) continue; 
     if (mi.IsFinal) 
      Console.WriteLine(mi.Name); 
     } 
    } 
    } 
+0

¿Entonces los métodos get/set se marcarán como finales? ¿Es posible que uno sea y no el otro? Gracias. –

+0

Tenga en cuenta el uso de "get_" y "set_" en el fragmento –

2

he aquí una solución modificada en base a la aplicación dada en this blog post:

var explicitProperties = 
    from prop in typeof(TempClass).GetProperties(
     BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly) 
    let getAccessor = prop.GetGetMethod(true) 
    where getAccessor.IsFinal && getAccessor.IsPrivate 
    select prop; 

foreach (var p in explicitProperties) 
    Console.WriteLine(p.Name); 
+0

¿Sabe si está bien suponer que getAccessor isPrivate? ¿Esto siempre será cierto? Además, los métodos get/set se marcarán como finales o es posible que uno sea y no el otro. Gracias. –

+0

La accesibilidad de ambos métodos será la misma para una propiedad explícitamente implementada. Los métodos serán ambos privados, desde la perspectiva del contrato de la clase. –

+0

al enumerar propiedades explícitas obtengo un error de referencia nulo. –

19

Creo que la clase que está buscando es System.Reflection.InterfaceMapping.

Type ifaceType = typeof(TempInterface); 
Type tempType = typeof(TempClass); 
InterfaceMapping map = tempType.GetInterfaceMap(ifaceType); 
for (int i = 0; i < map.InterfaceMethods.Length; i++) 
{ 
    MethodInfo ifaceMethod = map.InterfaceMethods[i]; 
    MethodInfo targetMethod = map.TargetMethods[i]; 
    Debug.WriteLine(String.Format("{0} maps to {1}", ifaceMethod, targetMethod)); 
} 
3

Basándose en el answer by MrKurt:

var targetMethods = 
    from iface in typeof(TempClass).GetInterfaces() 
    from method in typeof(TempClass).GetInterfaceMap(iface).TargetMethods 
    select method; 

var explicitProps = 
    from prop in typeof(TempClass).GetProperties(BindingFlags.Instance | 
               BindingFlags.NonPublic) 
    where targetMethods.Contains(prop.GetGetMethod(true)) || 
      targetMethods.Contains(prop.GetSetMethod(true)) 
    select prop; 
0

Esto parece un poco doloroso, sin razón aparente!

Mi solución es para el caso en que usted conoce el nombre de la propiedad que está buscando y es bastante simple.

Tengo una clase para hacer la reflexión un poco más fácil que sólo tenía que añadir a este caso:

public class PropertyInfoWrapper 
{ 
    private readonly object _parent; 
    private readonly PropertyInfo _property; 

    public PropertyInfoWrapper(object parent, string propertyToChange) 
    { 
     var type = parent.GetType(); 
     var privateProperties= type.GetProperties(BindingFlags.NonPublic | BindingFlags.Instance); 

     var property = type.GetProperty(propertyToChange) ?? 
         privateProperties.FirstOrDefault(p => UnQualifiedNameFor(p) == propertyName); 

     if (property == null) 
      throw new Exception(string.Format("cant find property |{0}|", propertyToChange)); 

     _parent = parent; 
     _property = property; 
    } 

    private static string UnQualifiedNameFor(PropertyInfo p) 
    { 
     return p.Name.Split('.').Last(); 
    } 

    public object Value 
    { 
     get { return _property.GetValue(_parent, null); } 
     set { _property.SetValue(_parent, value, null); } 
    } 
} 

Usted no puede simplemente hacer == en el nombre ya que las propiedades implementadas de manera explícita tienen nombres completos.

GetProperties necesita los dos indicadores de búsqueda para obtener propiedades privadas.

0

una clase de ayuda simple que podría ayudar:

public class InterfacesPropertiesMap 
{ 
    private readonly Dictionary<Type, PropertyInfo[]> map; 

    public InterfacesPropertiesMap(Type type) 
    { 
     this.Interfaces = type.GetInterfaces(); 
     var properties = type.GetProperties(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public); 

     this.map = new Dictionary<Type, PropertyInfo[]>(this.Interfaces.Length); 

     foreach (var intr in this.Interfaces) 
     { 
      var interfaceMap = type.GetInterfaceMap(intr); 
      this.map.Add(intr, properties.Where(p => interfaceMap.TargetMethods 
                .Any(t => t == p.GetGetMethod(true) || 
                   t == p.GetSetMethod(true))) 
             .Distinct().ToArray()); 
     } 
    } 

    public Type[] Interfaces { get; private set; } 

    public PropertyInfo[] this[Type interfaceType] 
    { 
     get { return this.map[interfaceType]; } 
    } 
} 

Usted obtendrá propiedades para cada interfaz, incluso en práctica de forma explícita.

Cuestiones relacionadas