none
インターフェイスに関連付けた属性 RRS feed

  • 質問

  • お世話になっております。

    [AttributeUsage(System.AttributeTargets.All, Inherited = true)]

    class Atr1 : System.Attribute { }

    [Atr1]class BaseClass { }

    [Atr1]interface IBaseClass { }

     

    class DerivedClass : BaseClass { } ①

    class DerivedClass : IBaseClass { } ②

    上記のDerivedClassクラスの属性値を下記のプログラムで取得しようとしていますが、

    ①では

    Attributes on Derived Class: ConsoleApplication1.Atr1

    ②では、

    Attributes on Derived Class:  (なし)

    となり、インターフェイスに付与した属性が取得できません。
    継承されているのかどうか確認したいのですが、どのようにすると取得できますか。
    教えてください。 

     

    public class TestAttributeUsage

    {

    static void Main()

    {

    DerivedClass d = new DerivedClass();

     

    Console.WriteLine("Attributes on Derived Class:");

    Object[] attrs = d.GetType().GetCustomAttributes(true);

    foreach (Attribute attr in attrs)

    {

    Console.WriteLine(attr);

    }

    }

    }

    }

    2011年8月11日 9:04

回答

  • インターフェースの属性は、タイプ ツリーからは手に入らないと思います。

    実装しているインターフェースの属性も検索したいならば、GetInterfaces() 等で実装インターフェースを列挙して、そのすべてのタイプ ツリーを検索する必要があるかと。

    IEnumerable<T> GetAttributesWithImplementedInterfaces<T>(Type t) where T : Attribute
    {
      foreach (var a in t.GetAttributes(typeof(T), true)) yield return (T) a;
      foreach (var a in t.GetInterfaces().Select(GetAttributesWithImplementedInterfaces<T>).SelectMany(i => i)) yield return (T) a;
    }

    foreach (var a in GetAttributesWithImplementedInterfaces(d.GetType()))
      Console.WriteLine(a);

    ためしてませんが、こんなかんじ。

    • 回答としてマーク OTAKA 2011年8月12日 0:58
    • 回答としてマークされていない OTAKA 2011年8月12日 0:58
    • 回答としてマーク OTAKA 2011年8月12日 0:58
    2011年8月11日 9:31
  • インターフェースは「実装」であって、継承・オーバーライドではないからです。
    # vtblとかわかると、AttriButeUsageAttribute.Inheritedが効かないのもわかるかなと。

    それはそうと、現実問題、インターフェースから属性を取得したくなることってあるのでしょうか?
    具体的な実装クラスを知らなくてもメソッド操作ができるようにするためのもので、つまりプログラムを書く際、インターフェースを知っているはずですが。

    • 回答としてマーク OTAKA 2011年8月12日 0:58
    2011年8月11日 12:09

すべての返信

  • インターフェースの属性は、タイプ ツリーからは手に入らないと思います。

    実装しているインターフェースの属性も検索したいならば、GetInterfaces() 等で実装インターフェースを列挙して、そのすべてのタイプ ツリーを検索する必要があるかと。

    IEnumerable<T> GetAttributesWithImplementedInterfaces<T>(Type t) where T : Attribute
    {
      foreach (var a in t.GetAttributes(typeof(T), true)) yield return (T) a;
      foreach (var a in t.GetInterfaces().Select(GetAttributesWithImplementedInterfaces<T>).SelectMany(i => i)) yield return (T) a;
    }

    foreach (var a in GetAttributesWithImplementedInterfaces(d.GetType()))
      Console.WriteLine(a);

    ためしてませんが、こんなかんじ。

    • 回答としてマーク OTAKA 2011年8月12日 0:58
    • 回答としてマークされていない OTAKA 2011年8月12日 0:58
    • 回答としてマーク OTAKA 2011年8月12日 0:58
    2011年8月11日 9:31
  • インターフェースは「実装」であって、継承・オーバーライドではないからです。
    # vtblとかわかると、AttriButeUsageAttribute.Inheritedが効かないのもわかるかなと。

    それはそうと、現実問題、インターフェースから属性を取得したくなることってあるのでしょうか?
    具体的な実装クラスを知らなくてもメソッド操作ができるようにするためのもので、つまりプログラムを書く際、インターフェースを知っているはずですが。

    • 回答としてマーク OTAKA 2011年8月12日 0:58
    2011年8月11日 12:09
  • ご返事ありがとうございます。

    この質問をする経緯ですが、ただいまWCF勉強中で、サービスコントラクト属性をインターフェイスに、そして実装をクラスにすることが推奨みたいな解説があり、
    ただ、ServiceContractAttributeクラスを確認したところ、Inheritedの値がfalseであったため、派生したクラスにはつかないのに大丈夫なん、
    本当かなと疑問をもち、上記サンプルプログラムを 使用して確認したところ、Inheritedの値がtrueであろうが、falseであろうが、属性が継承されていないので、
    質問にいたりました。 

    佐祐理氏の、説明で理解できました。

    >インターフェースは「実装」であって、継承・オーバーライドではないからです。

    p.s.
    WCFでの疑問の方は、おそらくインターフェイスにサービスコントラクト属性を付ける理由は、WSDL,XDLなどのメタファイル用か送信側の定義の用で
    実際メッセージを受信したときには、クラスのインスタンスを生成するメカニズムが別にあると推測し学習を進めたいと思います。 

     

    2011年8月12日 0:58