当前位置:  开发笔记 > 编程语言 > 正文

当一个属性隐藏一个带有'new'关键字的继承成员时,反射如何告诉我?

如何解决《当一个属性隐藏一个带有'new'关键字的继承成员时,反射如何告诉我?》经验,为你挑选了2个好方法。

所以,如果我有:

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之间做出不可知的答案



1> Greg Beech..:

我们必须在这里处理属性的方法而不是属性本身,因为它是属性的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 

因此我们可以从中看出,不可能纯粹从方法的元数据标记中分辨出是否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名称还是隐藏名称.

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

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

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



2> Tinister..:

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

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;
}

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

推荐阅读
Gbom2402851125
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有