I use a method similar to the following to get some precomputed metadata related to a Type's properties.
MyData GetProperty<T, U>(Expression<Func<T, U>> member)
{
// Get the property referenced in the lambda expression
MemberExpression expression = member.Body as MemberExpression;
PropertyInfo property = expression.Member as PropertyInfo;
// get the properties in the type T
PropertyInfo[] candidates = typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance);
// Find the match
foreach (PropertyInfo candidate in candidates)
if (candidate == property)
return GetMetaData<T>(candidate);
throw new Exception("Property not found.");
}
// Returns precomputed metadata
MyData GetMetaData<T>(PropertyInfo property) { ... }
As you would expect, it works when used as follows:
var data = PropertyInfo((Employee e) => e.Name);
But not when used in the following generic method:
void MyGenericMethod<T>(int id) where T : IEmployee
{
var data = PropertyInfo((T e) => e.Name);
}
It fails because the declaring type of property
in the first method is now IEmployee
, so the property in the lambda doesn't match the property in the type. How can I get them to match, without relying on the names of the properties? (There can be multiple properties with the same name if interfaces are implemented explicitly, so p1.Name == p2.Name
won't cut it).
What you'd probably need is an InterfaceMapping. You can get that from the actual type by calling
GetInterfaceMap(typeof(interface))
, i.e.,Now, the mapping will contain the fields
InterfaceMethods
which will contain the methods you see when reflecting the interface, andTargetMethods
which are the class's implementing methods. Note that this maps the the getter methods from the interface to the getter methods from the target class. You'll need to find the proper interface property by mapping the getter method of the various properties of the class to the found getter method.Caution: Note the use of
BindingFlags.NonPublic
andGetGetMethod(true)
here, for accessing private members. If you've got an explicit interface implementation, there isn't really a public property matching the interface's property, instead there is a private property namedSome.NameSpace.IEmployee.Name
that is mapped (which is, of course, your explicit implementation).When you've found the right property, you can just call
and you've got yourself a lambda expression that uses the class's properties rather than the interface's properties.
You'll need to get the member name from the lambda expression, and use reflection to get that member off of the type you've been given:
Here's proof that it works:
Console output:
Does BindingFlags.FlattenHierarchy work? If not, you could always iterate through
typeof(T).GetInterfaces
and callGetProperties
on each of them.