将接口的 ProperyInfo 与类的 PropertyInfo 相匹配

2024-04-14

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

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 中的属性与类型中的属性不匹配。我怎样才能让它们匹配,不依赖属性名称? (如果显式实现接口,则可以有多个同名属性,因此p1.Name == p2.Name不会削减它)。


你可能需要的是接口映射 http://msdn.microsoft.com/en-us/library/system.reflection.interfacemapping.aspx。您可以通过调用从实际类型中获取该值GetInterfaceMap(typeof(interface)), i.e.,

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

现在,映射将包含字段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

Caution:注意使用BindingFlags.NonPublic and 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);

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

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

将接口的 ProperyInfo 与类的 PropertyInfo 相匹配 的相关文章

随机推荐