21

だから私が持っている場合:

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の間で不可知であることを望みます

4

4 に答える 4

23

ここでは、プロパティ自体ではなく、プロパティのメソッドの観点から扱う必要があります。実際にオーバーライドされるのはプロパティ自体ではなく、プロパティの 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呼び出されるメソッドをシャドーすることができます-C#では答えはノーですが、VBで答えがイエスの場合、それはこの質問に対する答えが実際には非決定論的であることを意味します)。foohidebysig

ええと、これがどれだけ役立つかはわかりませんが、実際には私が思っていたよりもはるかに難しい問題であることを説明するためです (または、本当に明白なことを見逃している場合は知りたいです! )。しかし、うまくいけば、あなたがやろうとしていることを達成するのに役立つ十分なコンテンツが得られます.

于 2008-11-14T00:57:54.467 に答える
6

リフレクションがデフォルトでこれを提供するようには見えないので、自分でロールする必要があります。

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

ただし、これがインデックス付きプロパティでどのように機能するかはわかりません。

于 2008-11-13T23:13:47.233 に答える
0

私はあなたがやろうとしていることを決してしませんでしたが、 MethodInfo.GetBaseDefinition() メソッドはあなたが探しているもののようです。

このメソッドがオーバーライドしている MethodInfo を返します。

MSDN から:

特定のメソッドが new キーワードで指定されている場合 (型メンバーで説明されているニューススロットのように)、特定のメソッドが返されます。

于 2008-11-13T22:32:15.867 に答える
-1

VB を使用している場合、探しているプロパティは「IsHideBySig」です。メソッド/プロパティを定義するために「new」キーワードが使用された場合、これは false になります。

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
于 2008-11-13T21:22:58.550 に答える