16

以下のコードがあると想像してください。MemberInfo/PropertyInfoの「明示的な」実装のリフレクションを取得するにはどうすればよいTest.Nameですか?

MemberInfoまた、aがインターフェイス プロパティの明示的な実装であることをプログラムで知る方法はありますか?

public interface ITest
{
    string Title { get; set; }
}

public interface IExplicit
{
    string Name { get; set; }
}

public class Test : ITest,IExplicit
{

    public string Title { get; set; }

    string IExplict.Name
    {
        get
        {
            return this.Title;

        }
        set
        {

        }
    }
}
4

4 に答える 4

16

このインターフェースがあると想像してください:

interface ITest
{
    bool MyProperty { get; set; }
}

このクラスで実装:

class Test : ITest
{
    bool ITest.MyProperty { get; set; }
}

次に、このプロパティを次のように追加しましょう(名前が同じTestであることに注意してください)。

public bool MyProperty { get; set; }

プレーンGetProperties()は、明示的なインターフェイスの実装を取得できません (常にプライベート メンバーであるため)。

int count = new Test().GetType().GetProperties().Length; // It's 1!

Publicとメンバーの両方を含めると、両方NonPublicが得られます。それらを区別するには、最初に名前に頼ることができます: 明示的な実装には、完全なインターフェイス名が含まれます (そのため、 を探すことができます。通常の.プロパティには存在しません。これは許可された文字ではないためです)。

public static bool IsExplicitInterfaceImplementation(PropertyInfo property)
{
    return property.Name.Contains(".");
}

少し素朴なので、追加のチェックが必要な場合があります。そのプロパティの get メソッドは次のようになると断言できます。

  • virtualとですsealed
  • ですprivate
  • 少なくとも 1 つのドットが含まれます。
  • get_またはで始まらない_set

コードを変更しましょう:

public static bool IsExplicitInterfaceImplementation(PropertyInfo property)
{
    // This check is not mandatory and not cross-languages.
    // How this method is named may vary
    if (!property.Name.Contains("."))
        return false;

    if (property.Name.StartsWith("get_"))
        return false;

    if (!property.GetMethod.IsFinal)
        return false;

    if (!property.GetMethod.IsVirtual)
        return false;

    if (!property.GetMethod.IsPrivate)
        return false;

    return true;
}

もちろん、これらすべてのチェックが必要なわけではありません。最初の 2 つは、コンパイラによって生成されたコードのほとんどを除外するのに十分だと思います。

どのインターフェイスが明示的に実装されている可能性があるかがわかっている場合は、この質問が非常に便利であることがわかります。メソッドが特定のインターフェイスを実装しているかどうかを確認する方法

編集
コメントから私はこれについて考えましたが、それを行う適切な方法がないことがわかりました.CLRはルールを適用しません(AFAIK)。必要なのはインターフェイスメソッドとクラスメソッド間のリンクだけです(どのように呼び出されても)。私は推測します(ただし、他の言語では緩和または拡張される可能性があります。誰かがより多くのテストに貢献する場合は、この回答をwikiにします)このコードはほとんどの場合に機能する可能性があります(ヒントを提供してくれたAlxandrに感謝します):

メソッド (与えられた a MethodInfo) が明示的なインターフェイスの実装であるかどうかをチェックする最初のジェネリック関数。

断言できないこと:

  • 名前は実装に依存するため (たとえば "." などを確認するために)、名前を使用することはできません (C# は interfaceName.methodName を使用しますが、他の言語は使用しません)。

  • プライベートのチェックに頼ることはできません。たとえば、C++/CLI ではパブリック メソッド (別の名前を持つ) になる可能性があるためです。あまりにも公開しないでください)。

私たちが主張できること:

  • 明示的なインターフェイスの実装は、常に封印された仮想的なものです。すべての言語に当てはまるわけではないため、このルールを緩和することがあります。

  • メソッドが実装するインターフェースで宣言されたメソッドと同じ名前を持たない場合、それは明示的な実装です。

これはコードです:

public static bool IsExplicitInterfaceImplementation(MethodInfo method)
{
    // Check all interfaces implemented in the type that declares
    // the method we want to check, with this we'll exclude all methods
    // that don't implement an interface method
    var declaringType = method.DeclaringType;
    foreach (var implementedInterface in declaringType.GetInterfaces())
    {
        var mapping = declaringType.GetInterfaceMap(implementedInterface);

        // If interface isn't implemented in the type that owns
        // this method then we can ignore it (for sure it's not
        // an explicit implementation)
        if (mapping.TargetType != declaringType)
            continue;

        // Is this method the implementation of this interface?
        int methodIndex = Array.IndexOf(mapping.TargetMethods, method);
        if (methodIndex == -1)
            continue;

        // Is it true for any language? Can we just skip this check?
        if (!method.IsFinal || !method.IsVirtual)
            return false;

        // It's not required in all languages to implement every method
        // in the interface (if the type is abstract)
        string methodName = "";
        if (mapping.InterfaceMethods[methodIndex] != null)
            methodName = mapping.InterfaceMethods[methodIndex].Name;

        // If names don't match then it's explicit
        if (!method.Name.Equals(methodName, StringComparison.Ordinal))
            return true;
    }

    return false;
}

この補助関数を使用して、プロパティのチェックを行います。

public static bool IsExplicitInterfaceImplementation(PropertyInfo property)
{
    // At least one accessor must exists, I arbitrary check first for
    // "get" one. Note that in Managed C++ (not C++ CLI) these methods
    // are logically separated so they may follow different rules (one of them
    // is explicit and the other one is not). It's a pretty corner case
    // so we may just ignore it.
    if (property.GetMethod != null)
        return IsExplicitInterfaceImplementation(property.GetMethod);

    return IsExplicitInterfaceImplementation(property.SetMethod);
}
于 2013-07-25T09:27:24.843 に答える
1

インターフェイスとクラスの両方が同じ名前空間に存在する場合、これを試すことができます。

var interfaces = (typeof(Test)).GetInterfaces();
var p = typeof(Test).GetProperties(
    BindingFlags.Instance |
    BindingFlags.NonPublic);
var result = interfaces.SelectMany(i => i.GetMembers())
        .Select(m =>
        {
            var name = m.DeclaringType.FullName +"."+ m.Name;
            Console.WriteLine(name);
            return name;
        })
        .Intersect(p.Select(m =>
        {
            Console.WriteLine(m.Name);
            return m.Name;
        }))
        .ToList();
于 2013-07-25T09:32:31.340 に答える