所以,如果我有:
public class ChildClass : BaseClass
{
public new virtual string TempProperty { get; set; }
}
public class BaseClass
{
public virtual string TempProperty { get; set; }
}
我如何使用反射来查看ChildClass隐藏了TempProperty的Base实现?
我希望答案在C#和vb.net之间是不可知的
最佳答案
我们将不得不在这里处理属性的方法,而不是属性本身,因为实际上是覆盖属性的get/set方法而不是属性本身。我将使用get方法,因为即使没有完整的解决方案也应检查是否缺少一个属性,但您永远不应拥有一个属性。
查看在许多情况下发出的IL,基本属性的'get'方法将具有元数据 token (这是来自C#编译器;其他人可能不会发出hidebysig
,具体取决于他们的方法隐藏语义,在这种情况下,方法是按名称隐藏):
non-virtual : .method public hidebysig specialname instance
virtual : .method public hidebysig specialname newslot virtual instance
派生的将具有以下 token :
override : .method public hidebysig specialname virtual instance
new : .method public hidebysig specialname instance
new virtual : .method public hidebysig specialname newslot virtual instance
因此,我们可以看出,由于非虚拟基础方法与非虚拟
new
方法具有相同的 token ,并且虚拟基础方法具有与new
方法相同的标记。我们可以说的是,如果该方法具有
new virtual
token 但没有virtual
token ,则它会覆盖基本方法而不是对其进行阴影处理,即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'方法不是替代方法,我们想知道基类中是否有被遮盖的属性。问题在于,因为该方法位于不同的方法表插槽中,所以它实际上与它所隐藏的方法没有任何直接关系。因此,我们实际上要说的是“基本类型是否有符合阴影标准的任何方法”,具体取决于该方法是
newslot
还是按名称隐藏。对于前者,我们需要检查基类是否具有与签名完全匹配的方法,而对于后者,我们需要检查其是否具有相同名称的任何方法,因此从上面继续执行代码:
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中,如果它们都具有相同的签名并且都是
hidebysig
,那么称为Foo
的方法是否可以称为foo
的方法-在C#中答案为否,但如果答案为是,则在C#中VB,则意味着该问题的答案实际上是不确定的。好吧,我不确定这一切有多大的帮助,除了说明这实际上是一个比我想象的要困难得多的问题之外(或者我想知道在这种情况下我确实错过了一些明显的事情! )。但希望它有足够的内容,可以帮助您实现所要完成的任务。