我使用类似于以下的方法来获取一些与类型属性相关的预先计算的元数据。

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) { ... }

正如您所料,它在使用时的工作原理如下:
var data = PropertyInfo((Employee e) => e.Name);

但在以下通用方法中使用时则不然:
void MyGenericMethod<T>(int id) where T : IEmployee
{
    var data = PropertyInfo((T e) => e.Name);
}

它失败是因为第一个方法中 property 的声明类型现在是 IEmployee ,因此 lambda 中的属性与类型中的属性不匹配。 如何在不依赖属性名称的情况下让它们匹配 ? (如果接口(interface)是显式实现的,可以有多个同名的属性,所以 p1.Name == p2.Name 不会削减它)。

最佳答案

您可能需要的是 InterfaceMapping 。您可以通过调用 GetInterfaceMap(typeof(interface)) 从实际类型中获取它,即

InterfaceMapping mapping = typeof(Employee).GetInterfaceMap(typeof(IEmployee));

现在,映射将包含字段 InterfaceMethods ,其中包含您在反射(reflect)接口(interface)时看到的方法,以及 TargetMethods ,它们是类的实现方法。请注意,这将接口(interface)中的 getter 方法映射到目标类中的 getter 方法。您需要通过将类的各种属性的 getter 方法映射到找到的 getter 方法来找到正确的接口(interface)属性。
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

警告: 请注意此处使用 BindingFlags.NonPublicGetGetMethod(true) 来访问私有(private)成员。如果您有一个显式接口(interface)实现,那么实际上并没有与接口(interface)属性匹配的公共(public)属性,而是有一个名为 Some.NameSpace.IEmployee.Name 的私有(private)属性被映射(当然,这是您的显式实现)。

当您找到合适的房产后,您只需致电
ParameterExpression p = Expression.Parameter("e", typeof(T));
Expression<Func<T, U>> lambda = Expression.Lambda<Func<T, U>>(
    Expression.Property(p, targetProperty), p);

并且您已经获得了一个 lambda 表达式,它使用类的属性而不是接口(interface)的属性。

关于c# - 将接口(interface)的 PropertyInfo 与类的 PropertyInfo 匹配,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/3285392/

10-12 12:43
查看更多