【问题标题】:Identifying properties that override base properties or implement interfaces识别覆盖基本属性或实现接口的属性
【发布时间】:2011-03-18 13:56:52
【问题描述】:

我得到了:

  • 一个类“T”,它实现了用我感兴趣的属性修饰的属性。

  • A PropertyInfo "p" 表示属于 (1) T 实现的接口 "I" 的属性,(2) @987654328 的基类 "B" @ 继承自,或 (3) 类 T 本身。

即使p 的DeclaringType 是T 实现的接口或T 继承自的类,我也需要获取在T 中的属性上定义(或由其继承)的属性。所以我需要一种方法来从pT 上实际存在的PropertyInfo。因此似乎有3种情况:

  1. p.DeclaringType == typeof(T)

    这是一个小例子。我可以遍历T 的属性,直到找到匹配项。示例:

    return typeof(T).GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
                    .FirstOrDefault(property => property == p)
    
  2. p.DeclaringType == typeof(I) 其中IT 实现的接口

    这更复杂。发现可以使用一个InterfaceMapping在T中找到p的对应实现。这似乎有点骇人听闻,但这里有什么作用:

    if (p.DeclaringType.IsInterface &&
        typeof(T).GetInterfaces().Contains(p.DeclaringType))
    {
        InterfaceMapping map = typeof(T).GetInterfaceMap(p.DeclaringType);
        MethodInfo getMethod = p.GetGetMethod();
        for (int i = 0; i < map.InterfaceMethods.Length; i++)
        {
            if (map.InterfaceMethods[i] == getMethod)
            {
                MethodInfo target = map.TargetMethods[i];
                return typeof(T).GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
                                .FirstOrDefault(property => property.GetGetMethod() == target);
            }
        }
    }
    
  3. p.DeclaringType == typeof(B) 其中BT 继承自的类

    我还没有弄清楚如何识别T 上的属性,它覆盖了Ts 基类B 中定义的虚拟属性p

所以我的问题是

  • 案例 3中,我如何在 T 上找到覆盖 B 上的属性 pPropertyInfo
  • 有没有更好的方法来完成这三个?也许是一种统一这三种情况的方法。

【问题讨论】:

  • 无论你的解决方案最终是什么,不要忘记一个类可以隐藏(或隐藏)一个继承的成员(msdn.microsoft.com/en-us/library/…)这一事实。这可能会影响您的解决方案。

标签: c# .net reflection .net-3.5


【解决方案1】:

我认为您遗漏了一个案例:T 可能只是从 B 继承该属性,而没有覆盖它(除非您确定这不会在您的特定场景中发生)。

无论如何,您只需要按名称搜索属性,使用typeof(T).GetProperty,因为在给定的类中不能有两个同名的属性(与方法不同,方法可以有多个重载)。但是,您需要注意T 使用new 修饰符隐藏B 继承的属性的情况。要处理这种情况,您可以检查属性的 getter 方法的 Attributes(使用 GetGetMethod 获得):如果存在 NewSlot 标志,它会隐藏继承的 getter。

【讨论】:

  • 显式实现接口时,属性可以同名。
【解决方案2】:

我找到了回答案例 3 的方法。关键是MethodInfo.GetBaseDefinition

if (typeof(T).IsSubclassOf(p.DeclaringType))
{
    MethodInfo baseDefinition = p.GetGetMethod().GetBaseDefinition();
    return typeof(T).GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
                    .FirstOrDefault(property => property.GetGetMethod().GetBaseDefinition() == baseDefinition);
}

但这仅适用于在 T 上被覆盖的属性。

编辑:

通过比较以下内容,T 上的属性是否已被覆盖并不重要:

property.GetGetMethod().GetBaseDefinition().MetadataToken == baseDefinition.MetadataToken

【讨论】:

  • 大胖警告:正如文档所述,MetadataToken 仅在每个模块中是唯一的。在测试您的答案时,我碰巧偶然发现了同一类中的两个属性,它们的基本 getter 方法 MetadataToken 相同,因为其中一个是在另一个库中定义的。 (幸运的是,该类恰好是基类的 *Test 实现,而我的一些测试失败了。)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-08-18
  • 2014-09-19
  • 1970-01-01
  • 2012-06-30
  • 2019-04-02
  • 2013-07-19
相关资源
最近更新 更多