方法也一样:
我得到了两个 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
对象,我们可以得出以下结论:
- 没有直接的方法可以查看属性最初是在哪个类/接口(interface)上声明的。
- 因此,要检查该属性是否实际上是在祖先类上声明的,我们需要遍历祖先类并查看该属性是否也存在于它们上。
- 接口(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/