c# - 如何可靠地比较两个 PropertyInfos 或方法?

标签 c# reflection

方法也一样:

我得到了两个 PropertyInfo 实例或方法,它们是通过 GetProperty()GetMember() 等从它们所在的类中提取的(或从MemberExpression 也许)。

我想确定它们实际上是指相同的属性还是相同的方法

(propertyOne == propertyTwo)

(methodOne == methodTwo)

显然这不会真正起作用,您可能正在查看相同的属性,但它可能是从类层次结构的不同级别提取的(在这种情况下,通常 propertyOne != propertyTwo)

当然,我可以查看 DeclaringType,然后重新请求该属性,但是当您开始考虑时,这会开始变得有点困惑

  • 在接口(interface)上声明并在类上实现的属性/方法
  • 在基类上(虚拟地)声明并在派生类上覆盖的属性/方法
  • 在基类上声明的属性/方法,用“new”覆盖(在 IL 世界中这没什么特别的 iirc)

归根结底,我只想能够在两个属性或两个方法之间进行智能相等性检查,我有 80% 的把握上述要点不会涵盖所有边缘情况,虽然我可以坐下来,编写一堆测试并开始尝试,但我很清楚我对这些概念的实际实现方式的低级知识并不出色,而且我希望这是一个已经回答的话题,我只是不擅长搜索。

最好的答案会给我一些实现上述目标的方法,解释已经处理了哪些边缘情况以及为什么:-)


澄清:

从字面上看,我想确保它们是相同的属性,这里有一些例子

public interface IFoo
{
     string Bar { get; set; }
}

public class Foo : IFoo
{
     string Bar { get; set; }
}

typeof(IFoo).GetProperty("Bar")

typeof(Foo).GetProperty("Bar")

将返回两个不相等的属性信息:

public class BaseClass
{
     public string SomeProperty { get; set ; }
}

public class DerivedClass : BaseClass { }


typeof(BaseClass).GetMethod("SomeProperty")

typeof(DerivedClass).GetProperty("SomeProperty")

我实际上不记得这两个现在返回的对象是否相等,但在我的世界中它们是相等的。

类似地:

public class BaseClass
{
    public virtual SomeMethod() { }
}

public class DerivedClass
{
    public override SomeMethod() { }
}

typeof(BaseClass).GetMethod("SomeMethod")

typeof(DerivedClass).GetProperty("SomeMethod")

同样,它们不匹配 - 但我希望它们匹配(我知道它们并不特别相等,但在我的域中它们是因为它们引用相同的原始属性)

我可以在结构上做到这一点,但那将是“错误的”。

进一步说明:

您如何请求隐藏另一个属性的属性?似乎我之前的假设之一是无效的,GetProperty("name") 的默认实现将默认引用当前级别。

BindingFlags.DeclaringType 似乎只是以返回 null 结束!

最佳答案

查看 IFoo/Foo 示例中的 PropertyInfo 对象,我们可以得出以下结论:

  1. 没有直接的方法可以查看属性最初是在哪个类/接口(interface)上声明的。
  2. 因此,要检查该属性是否实际上是在祖先类上声明的,我们需要遍历祖先类并查看该属性是否也存在于它们上。
  3. 接口(interface)也是如此,我们需要调用 Type.GetInterfaces 并从那里开始工作。不要忘记接口(interface)可以实现其他接口(interface),因此这必须是递归的。

让我们开始吧。首先,覆盖继承属性:

PropertyInfo GetRootProperty(PropertyInfo pi)
{
    var type = pi.DeclaringType;

    while (true) {
        type = type.BaseType;

        if (type == null) {
            return pi;
        }

        var flags = BindingFlags.NonPublic | BindingFlags.DeclaredOnly | BindingFlags.Instance |
                    BindingFlags.Public | BindingFlags.Static;
        var inheritedProperty = type.GetProperty(pi.Name, flags);

        if (inheritedProperty == null) {
            return pi;
        }

        pi = inheritedProperty;
    }
}

现在,覆盖接口(interface)中声明的属性(使用 DFS 搜索):

PropertyInfo GetImplementedProperty(PropertyInfo pi)
{
    var type = pi.DeclaringType;
    var interfaces = type.GetInterfaces();

    if (interfaces.Length == 0) {
        return pi;
    }

    var flags = BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public;
    var query = from iface in interfaces
                let implementedProperty = iface.GetProperty(pi.Name, flags)
                where implementedProperty != pi
                select implementedProperty;

    return query.DefaultIfEmpty(pi).First();
}

将它们结合在一起:

PropertyInfo GetSourceProperty(PropertyInfo pi)
{
    var inherited = this.GetRootProperty(pi);
    if (inherited != pi) {
        return inherited;
    }

    var implemented = this.GetImplementedProperty(pi);
    if (implemented != pi) {
        return implemented;
    }

    return pi;
}

这应该有效。它不考虑具有相同名称但不同类型和/或数量的索引参数的索引属性,因此留给读者作为众所周知的练习。

免责声明:我什至没有编译它(现在没有时间运行测试)。它旨在作为“那个”答案的起点,因为目前还没有答案。

关于c# - 如何可靠地比较两个 PropertyInfos 或方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4640709/

相关文章:

c# - 如何通过代码添加事件 setter

c# - 获取在线文件 [http] 大小的最快方法是什么

c# - 如何在 C# 中以编程方式为 WPF 工具包数据网格创建列?

java - 带有类名的字符串并获取Class.class

java - 将逻辑注入(inject)到 spring 组件扫描过程中

swift - 检查对象是否是 Swift 中类元类型的实例

java - 使用反射创建新对象?

java - 使用 class.getDeclaredMethod 反射(reflect)方法时不存在注释

c# - 加载 PDF 文档时出错 - iTextSharp PDF

c# - 使用 HtmlAgilityPack .NET 解析出 iframe 中的隐藏字段