我们必须在这里处理属性的方法而不是属性本身,因为实际上被覆盖的是属性的 get/set 方法而不是属性本身。我将使用 get 方法,因为您永远不应该拥有一个没有属性的属性,尽管完整的解决方案应该检查是否缺少属性。
查看在许多情况下发出的 IL,基本属性的“get”方法将具有元数据标记(这是来自 C# 编译器;其他人可能不会发出hidebysig
取决于他们的方法隐藏语义,在这种情况下方法将按名称隐藏):
non-virtual : .method public hidebysig specialname instance
virtual : .method public hidebysig specialname newslot virtual instance
派生的将具有以下标记:
override : .method public hidebysig specialname virtual instance
new : .method public hidebysig specialname instance
new virtual : .method public hidebysig specialname newslot virtual instance
所以由此我们可以看出,单纯从方法的元数据token中是无法判断是不是new
因为non-virtual base方法和non-virtual方法有相同token new
,而virtual base方法有相同token作为new virtual
方法。
我们可以说的是,如果方法有virtual
令牌但没有newslot
令牌,那么它会覆盖一个基本方法而不是隐藏它,即
var prop = typeof(ChildClass).GetProperty("TempProperty");
var getMethod = prop.GetGetMethod();
if ((getMethod.Attributes & MethodAttributes.Virtual) != 0 &&
(getMethod.Attributes & MethodAttributes.NewSlot) == 0)
{
// the property's 'get' method is an override
}
那么,假设我们发现 'get' 方法不是覆盖,我们想知道基类中是否存在它正在遮蔽的属性。问题在于,由于该方法位于不同的方法表槽中,因此它实际上与它所映射的方法没有任何直接关系。所以我们实际上要说的是“基础类型是否有任何满足遮蔽标准的方法”,这取决于方法是hidebysig
按名称隐藏还是按名称隐藏。
对于前者,我们需要检查基类是否有任何与签名完全匹配的方法,而对于后者,我们需要检查它是否有任何同名的方法,所以继续上面的代码:
else
{
if (getMethod.IsHideBySig)
{
var flags = getMethod.IsPublic ? BindingFlags.Public : BindingFlags.NonPublic;
flags |= getMethod.IsStatic ? BindingFlags.Static : BindingFlags.Instance;
var paramTypes = getMethod.GetParameters().Select(p => p.ParameterType).ToArray();
if (getMethod.DeclaringType.BaseType.GetMethod(getMethod.Name, flags, null, paramTypes, null) != null)
{
// the property's 'get' method shadows by signature
}
}
else
{
var flags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance;
if (getMethod.DeclaringType.BaseType.GetMethods(flags).Any(m => m.Name == getMethod.Name))
{
// the property's 'get' method shadows by name
}
}
}
我认为这是大部分的方式,但我仍然不认为这是完全正确的。首先,我并不完全熟悉按名称隐藏,因为 C# 不支持它,而这几乎就是我使用的全部内容,所以我在这里的代码中可能是错误的,表明实例方法可能会影响静态方法。我也不知道区分大小写的问题(例如,在 VB 中,如果它们都具有相同的签名并且两者都具有相同的签名,则可以调用一个名为Foo
shadow 的方法- 在 C# 中答案是否定的,但如果在 VB 中答案是肯定的,那么它意味着这个问题的答案实际上是不确定的)。foo
hidebysig
好吧,我不确定这一切有多大帮助,除了说明它实际上是一个比我想象的要困难得多的问题(或者我错过了一些非常明显的事情,在这种情况下我想知道! )。但希望它有足够的内容来帮助你实现你想要做的事情。