当一个属性隐藏带有’new’关键字的inheritance成员时,reflection如何告诉我?

如果我有:

public class ChildClass : BaseClass { public new virtual string TempProperty { get; set; } } public class BaseClass { public virtual string TempProperty { get; set; } } 

如何使用reflection来查看ChildClass是否隐藏了TempProperty的Base实现?

我想在c#和vb.net之间做出不可知的答案

我们必须在这里处理属性的方法而不是属性本身,因为它是属性的get / set方法,实际上被覆盖而不是属性本身。 我将使用get方法,因为你应该永远没有一个属性,尽管一个完整的解决方案应该检查缺少一个。

查看在许多情况下发出的IL,base属性的’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 

因此我们可以从中看出,由于非虚拟基本方法与非虚拟new方法具有相同的标记,并且虚拟基本方法具有相同的标记,因此不可能完全从方法的元数据标记中判断它是否是new的。与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还是hide-by-name。

对于前者,我们需要检查基类是否具有与签名完全匹配的任何方法,而对于后者,我们需要检查它是否具有任何具有相同名称的方法,因此继续上面的代码:

 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的方法,如果它们都具有相同的签名并且都是hidebysig那么这个方法称为foo ,在C#中答案是否定的,但如果答案是肯定的,那么VB然后它意味着这个问题的答案实际上是不确定的)。

好吧,我不确定这一切有多大帮助,除了说明它实际上比我想象的要困难得多(或者我错过了一些非常明显的东西,在这种情况下我想知道! )。 但希望它有足够的内容,它可以帮助你实现你想要做的事情。

看起来不像reflection会默认给你这样你所以你必须自己动手:

 public static bool IsHidingMember( this PropertyInfo self ) { Type baseType = self.DeclaringType.BaseType; PropertyInfo baseProperty = baseType.GetProperty( self.Name, self.PropertyType ); if ( baseProperty == null ) { return false; } if ( baseProperty.DeclaringType == self.DeclaringType ) { return false; } var baseMethodDefinition = baseProperty.GetGetMethod().GetBaseDefinition(); var thisMethodDefinition = self.GetGetMethod().GetBaseDefinition(); return baseMethodDefinition.DeclaringType != thisMethodDefinition.DeclaringType; } 

但是,不知道这对索引属性如何起作用!

我从未做过你想要做的事,但是MethodInfo.GetBaseDefinition()方法似乎就是你要找的。

它返回MethodInfo,此方法重写。

来自MSDN:

如果使用new关键字指定给定方法(如在类型成员中所述的新闻时段中),则返回给定方法。

更正,如果您使用VB,您正在寻找的属性是“IsHideBySig”。 在使用“new”关键字定义方法/属性的情况下,这将是错误的。

在C#情况下,两个实例都输出为“hidebysig”。 谢谢你指出格雷格。 我没有意识到我只在VB中测试过这个。 这是将重现此行为的示例VB代码。

 Module Module1 Class Foo Public Function SomeFunc() As Integer Return 42 End Function End Class Class Bar Inherits Foo Public Shadows Function SomeFunc() As Integer Return 36 End Function End Class Sub Main() Dim type = GetType(Bar) Dim func = type.GetMethod("SomeFunc") Stop End Sub End Module