2008-11-10 5 views
19

Mehr, wenn ich:Wie verwende ich Reflektion, um Eigenschaften zu erhalten, die explizit eine Schnittstelle implementieren? speziell

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

Wie verwende ich die Reflexion propertyInfos alle Objekte der Umsetzung TempInterface ausdrücklich zu bekommen?

Danke.

+0

Können Sie genau erklären, was Sie suchen? Möchten Sie nur eine Liste aller Eigenschaften, die von TempClass explizit implementiert wurden?Oder möchten Sie nur die Eigenschaften von TempInterface? usw. –

+0

Ich möchte eine Liste aller Eigenschaften, die explizit von TempClass implementiert werden –

Antwort

1

ich Jacob Carpenter Antwort ändern musste, aber es funktioniert gut. Nobugz funktioniert auch, aber Jacobs ist kompakter.

+0

Ihre Antwort ist Methoden zu erhalten, Jacobs bekommt die Eigenschaften, wie Sie ursprünglich in der Frage gefragt haben. – nawfal

1

Es ist übermäßig komplex. Sie müssen über die Methoden/Eigenschaften des Interface-Typs nachdenken, sehen, ob sie in Ihrem Klassentyp vorhanden sind, und sie vergleichen, um zu sehen, ob sie "gleich" sind, wenn sie existieren.

Wenn etwas in der Schnittstelle ist, aber nicht den Typ, den Sie testen, ist es eine explizite Implementierung. Wenn es in beiden ist, aber unterschiedlich zwischen den beiden, ist es eine explizite Schnittstelle.

+0

Wenn eine Klasse eine Schnittstelle implementiert, implementiert sie alle Eigenschaften und Methoden in dieser Schnittstelle. Damit Sie die Mitglieder der Klasse nicht untersuchen müssen, müssen Sie nur die Mitglieder der Schnittstelle untersuchen. –

+0

Sie müssen die Interface-Mitglieder mit den Klassenmitgliedern vergleichen, um herauszufinden, ob das Mitglied * explizit * implementiert ist oder nicht. – MrKurt

0

Jakobs Code fehlt einen Filter:

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

Wenn Sie nur die Interface-Eigenschaften von TempInterfaces wollen, warum nicht mit typeof (TempInterface) anfangen? –

+1

Weil das erfordert, dass ich schlauer bin als ich. –

4

Die Eigenschaft Getter und Setter einer explizit implementierte Schnittstelle Eigenschaft hat eine ungewöhnliche Eigenschaft. Es ist IsFinal-Eigenschaft True, auch wenn es kein Mitglied einer versiegelten Klasse ist. Versuchen Sie diesen Code meine Behauptung zu überprüfen:

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

Also beide Get/Set-Methoden werden als endgültig markiert? Ist es möglich, dass einer ist und nicht der andere? Vielen Dank. –

+0

Beachten Sie die Verwendung von "get_" und "set_" im Snippet –

2

Hier ist eine modifizierte Lösung basierend auf der Implementierung gegeben in 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

Wissen Sie, ob es ok ist, den getAccessor isPrivate anzunehmen? Wird das immer wahr sein? Werden beide Get/Set-Methoden auch als final gekennzeichnet oder ist es möglich, dass die eine Methode die andere ist? Vielen Dank. –

+0

Die Barrierefreiheit beider Methoden ist für eine explizit implementierte Eigenschaft gleich. Die Methoden werden beide privat sein, aus Sicht des Klassenvertrags. –

+0

Beim Aufzählen von ExplicitProperties erhalte ich einen Nullreferenzfehler. –

19

Ich denke, dass die Klasse, nach der Sie suchen, System.Reflection.InterfaceMapping ist.

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

Aufbauend auf dem 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

Dies scheint ein wenig schmerzhaft ohne ersichtlichen Grund!

Meine Lösung ist für den Fall, dass Sie den Namen der Eigenschaft kennen, die Sie suchen, und ist ziemlich einfach.

Ich habe eine Klasse für die Herstellung von Reflexion etwas einfacher, dass ich nur auf diesen Fall hinzufügen:

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

You cant == auf den Namen nur tun, weil explizit implementiert Eigenschaften voll qualifizierten Namen haben.

GetProperties benötigt beide Such-Flags, um an private Eigenschaften zu gelangen.

0

Eine einfache Hilfsklasse, die helfen könnten:

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

Sie werden für jede Schnittstelle erhalten Eigenschaften, sogar explizit umgesetzt.

Verwandte Themen