How do I use reflection to get properties explicitly implementing an interface?
Asked Answered
P

9

30

More specifically, if I have:

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

How do I use reflection to get all the propertyInfos for properties explicitly implementing TempInterface?

Thanks.

Promissory answered 10/11, 2008 at 20:6 Comment(2)
Can you clarify exactly what you're looking for? Do you just want a list of all properties explicitly implemented by TempClass? Or do you just want the properties of TempInterface? etc.Cannibal
I want a list of all the properties explicitly implemented by TempClassAntimonic
P
1

I had to modify Jacob Carpenter's answer but it works nicely. nobugz's also works but Jacobs is more compact.

var explicitProperties =
from method in typeof(TempClass).GetMethods(BindingFlags.NonPublic | BindingFlags.Instance)
where method.IsFinal && method.IsPrivate
select method;
Promissory answered 11/5, 2009 at 14:45 Comment(1)
Your answer is getting methods, Jacob's is getting the properties as you asked in the question originally.Bilateral
M
28

I think the class you are looking for is 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));
}
Microscopic answered 18/6, 2009 at 22:50 Comment(0)
E
5

The property getter and setter of an explicitly implemented interface property has an unusual attribute. It's IsFinal property is True, even when it is not a member of a sealed class. Try this code to verify my assertion:

  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);
      }
    }
  }
Englis answered 10/11, 2008 at 20:56 Comment(2)
So both the get/set methods will be marked final? Is it possible for one to be and not the other? thanks.Antimonic
Note the use of "get_" and "set_" in the snippetEnglis
C
4

Here's a modified solution based on the implementation given 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);
Cannibal answered 11/11, 2008 at 1:40 Comment(4)
Do you know if its ok to assume the getAccessor isPrivate? Will this always be true? Also, will both the get/set methods be marked final or is it possible for one to be and not the other. thanks.Antimonic
The accessibility of both methods will be the same for an explicitly implemented property. The methods will both be private, from the perspective of the class's contract.Cannibal
when enumerating explicitProperties I get a null reference error.Antimonic
I think GetProperties can't be used.Antimonic
S
3

Building on the 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;
Shatterproof answered 30/6, 2011 at 3:6 Comment(0)
W
1

It's overly complex. You have to reflect over the methods/properties of the Interface type, see if they exist in your class type, and compare them to see if they're the "same" when they do exist.

If something is in the interface but not the type you're testing, it's an explicit implementation. If it's in both, but different between the two, it's an explicit interface.

Wohlert answered 10/11, 2008 at 20:13 Comment(2)
If a class implements an interface, it implements all properties and methods in that interface. So you don't have to examine the members of the class, you just have to examine the members of the interface.Wyatan
You have to compare the interface members to the class members to find out if the member is explicitly implemented or not.Wohlert
P
1

I had to modify Jacob Carpenter's answer but it works nicely. nobugz's also works but Jacobs is more compact.

var explicitProperties =
from method in typeof(TempClass).GetMethods(BindingFlags.NonPublic | BindingFlags.Instance)
where method.IsFinal && method.IsPrivate
select method;
Promissory answered 11/5, 2009 at 14:45 Comment(1)
Your answer is getting methods, Jacob's is getting the properties as you asked in the question originally.Bilateral
H
1

A simple helper class that could help:

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

You'll get properties for each interface, even explicitly implemented.

Hypochlorite answered 17/4, 2012 at 13:5 Comment(0)
N
0

This seems a bit painful for no apparent reason!

My solution is for the case where you know the name of the property you are looking for and is pretty simple.

I have a class for making reflection a bit easier that I just had to add this case to:

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 just do == on name because explicitly implemented properties have fully qualified names.

GetProperties needs both the search flags to get at private properties.

Normative answered 24/10, 2011 at 16:20 Comment(0)
W
-1

Jacob's code is missing a filter:

        var props = typeof(TempClass).GetInterfaces().Where(i => i.Name=="TempInterface").SelectMany(i => i.GetProperties());
        foreach (var prop in props)
            Console.WriteLine(prop);
Wyatan answered 10/11, 2008 at 20:40 Comment(2)
If you only want the interface properties of TempInterfaces, why not start with typeof(TempInterface)?Cannibal
Because that would require me to be smarter than I am.Wyatan

© 2022 - 2024 — McMap. All rights reserved.