Gre*_*reg 3 .net c# reflection
我使用类似于以下的方法来获取与Type的属性相关的一些预先计算的元数据.
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) { ... }
Run Code Online (Sandbox Code Playgroud)
正如您所料,它的使用方式如下:
var data = PropertyInfo((Employee e) => e.Name);
Run Code Online (Sandbox Code Playgroud)
但是在以下通用方法中使用时不是:
void MyGenericMethod<T>(int id) where T : IEmployee
{
var data = PropertyInfo((T e) => e.Name);
}
Run Code Online (Sandbox Code Playgroud)
它失败是因为property第一种方法中的声明类型现在是IEmployee,因此lambda中的属性与该类型中的属性不匹配.如何在不依赖属性名称的情况下让它们匹配?(如果明确实现接口,则可以有多个具有相同名称的属性,因此p1.Name == p2.Name不会删除它).
您可能需要的是InterfaceMapping.您可以通过调用从实际类型中获取GetInterfaceMap(typeof(interface)),即
InterfaceMapping mapping = typeof(Employee).GetInterfaceMap(typeof(IEmployee));
Run Code Online (Sandbox Code Playgroud)
现在,映射将包含InterfaceMethods将包含您在反映界面时看到的方法的字段,以及TargetMethods哪些是类的实现方法.请注意,这会将getter方法从接口映射到目标类的getter方法.您需要通过将类的各种属性的getter方法映射到找到的getter方法来找到正确的接口属性.
Type interfaceType = typeof(IEmployee);
Type classType = typeof(Employee);
PropertyInfo nameProperty = interfaceType.GetProperty("Name");
MethodInfo nameGetter = nameProperty.GetGetMethod();
InterfaceMapping mapping = classType.GetInterfaceMap(interfaceType);
MethodInfo targetMethod = null;
for (int i = 0; i < mapping.InterfaceMethods.Length; i++)
{
if (mapping.InterfaceMethods[i] == nameGetter)
{
targetMethod = mapping.TargetMethods[i];
break;
}
}
PropertyInfo targetProperty = null;
foreach (PropertyInfo property in classType.GetProperties(
BindingFlags.Instance | BindingFlags.GetProperty |
BindingFlags.Public | BindingFlags.NonPublic)) // include non-public!
{
if (targetMethod == property.GetGetMethod(true)) // include non-public!
{
targetProperty = property;
break;
}
}
// targetProperty is the actual property
Run Code Online (Sandbox Code Playgroud)
注意:请注意使用BindingFlags.NonPublic和GetGetMethod(true)此处访问私有成员.如果你有一个显式的接口实现,那么实际上并没有一个匹配接口属性的公共属性,而是有一个名为Some.NameSpace.IEmployee.Name的映射的私有属性(当然,这是你的显式实现).
当您找到合适的房产时,您可以打电话
ParameterExpression p = Expression.Parameter("e", typeof(T));
Expression<Func<T, U>> lambda = Expression.Lambda<Func<T, U>>(
Expression.Property(p, targetProperty), p);
Run Code Online (Sandbox Code Playgroud)
并且你有一个lambda表达式,它使用类的属性而不是接口的属性.