所以如果我有:

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,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 virtual方法具有相同的标记,并且虚拟基本方法与virtual方法具有相同的标记。

我们可以说的是,如果该方法具有newslot标记而不是Foo标记,那么它会覆盖基本方法而不是隐藏它,即

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'方法不是覆盖,我们想知道基类中是否存在阴影属性。问题是因为该方法位于不同的方法表槽中,它实际上与它所遮蔽的方法没有任何直接关系。所以我们实际上说的是<!>“;基类型是否有任何符合阴影<!>”的标准的方法,这取决于方法是foo还是隐藏名称。

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

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中可以使用一种称为<=>阴影的方法,如果它们都具有相同的签名并且两者都具有相同的签名,那么<=>影子<=> - 在C#中答案是否定的如果VB中的答案是肯定的,那么这意味着这个问题的答案实际上是不确定的。)

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

其他提示

默认情况下,反射看起来不会给你这样做,所以你必须自己动手:

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 <!> quot;。在<!>“new <!>”的情况下,这将是错误的。 keyword用于定义方法/属性。

在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
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top