C# リフレクション

C# リフレクション

リフレクションとは、プログラムが自身の状態や動作にアクセス、検出、および変更する機能を指します。リフレクションは、アセンブリ、モジュール、および型を記述するために使用されるオブジェクトを提供します。リフレクションを使用すると、型のインスタンスを動的に作成したり、型をバインドしたりすることができます。既存のオブジェクトを取得するか、既存のオブジェクトから型を取得して、そのメソッドを呼び出すか、そのフィールドとプロパティにアクセスします。コードで属性が使用されている場合は、リフレクションを使用してアクセスすることもできます。

反射の使用

C# のリフレクションには次のような用途があります。

  • 実行時にビュー属性情報を表示します。
  • アセンブリ内のさまざまな型を確認し、それらの型をインスタンス化します。
  • メソッドとプロパティへの遅延バインディング。
  • 実行時に新しいタイプを作成し、それらのタイプを使用していくつかのタスクを実行します。

メタデータを表示する

リフレクションを使用して機能に関する情報を表示できることを前述したので、具体的な操作手順を見てみましょう。まず、System.Reflection クラスの MemberInfo オブジェクトを初期化して、クラスに関連付けられた属性を検出する必要があります。次に例を示します。

System.Reflection.MemberInfo info = typeof(MyClass);

完全なサンプルコードは次のとおりです。

using System;

[AttributeUsage(AttributeTargets.All)]
public class HelpAttribute : System.Attribute {
    public readonly string Url;
  
    public string Topic   // Topic は name_parameterです
    {
        get {
            return topic;
        }
        set {
            topic = value;
        }
    }
    public HelpAttribute(string url)   // url は positional_parametersです
    {
        this.Url = url;
    }
    private string topic;
}

[HelpAttribute("MyClassについての情報")]
class MyClass {

}

namespace it-kiso.com
{
    class Demo
    {
        static void Main(string[] args) 
        {
            System.Reflection.MemberInfo info = typeof(MyClass);
            object[] attributes = info.GetCustomAttributes(true);
        
            for (int i = 0; i < attributes.Length; i++) {
                System.Console.WriteLine(attributes[i]);
            }
            Console.ReadKey();
        }
    }
} 

操作の結果は次のようになります。

HelpAttribute

[例] この例では、前セクションで作成した DeBugInfo 機能を使用し、Reflection を使用して Rectangle クラスのメタデータを読み取ります。

 using System;
using System.Reflection;

namespace it-kiso.com
{
    // クラスやメンバーに割り当てるカスタム属性のデバッグ修正プログラム
    [AttributeUsage(
    AttributeTargets.Class |
    AttributeTargets.Constructor |
    AttributeTargets.Field |
    AttributeTargets.Method |
    AttributeTargets.Property,
    AllowMultiple = true)]

    public class DeBugInfo : System.Attribute {
        private int bugNo;
        private string developer;
        private string lastReview;
        public string message;

        public DeBugInfo(int bg, string dev, string d) {
            this.bugNo = bg;
            this.developer = dev;
            this.lastReview = d;
        }
        public int BugNo {
            get {
                return bugNo;
            }
        }
        public string Developer {
            get {
                return developer;
            }
        }
        public string LastReview {
            get {
                return lastReview;
            }
        }
        public string Message {
            get {
                return message;
            }
            set {
                message = value;
            }
        }
    }
    [DeBugInfo(45, "Zara Ali", "12/8/2012", Message = "戻り値の型が一致しません")]
    [DeBugInfo(49, "Nuha Ali", "10/10/2012", Message = "未使用の変数")]

    class Rectangle {
        // メンバ変数
        protected double length;
        protected double width;

        public Rectangle(double l, double w) {
            length = l;
            width = w;
        }
        [DeBugInfo(55, "Zara Ali", "19/10/2012", Message = "戻り値の型が一致しません")]
        public double GetArea() {
            return length * width;
        }
        [DeBugInfo(56, "Zara Ali", "19/10/2012")]
        public void Display() {
            Console.WriteLine("長さ: {0}", length);
            Console.WriteLine("幅: {0}", width);
            Console.WriteLine("面積: {0}", GetArea());
        }
    }

    class Demo
    {
        static void Main(string[] args) 
        {
            Rectangle r = new Rectangle(4.5, 7.5);
            r.Display();
            Type type = typeof(Rectangle);

            // Rectangleクラスの属性をループする
            foreach (Object attributes in type.GetCustomAttributes(false)) {
                DeBugInfo dbi = (DeBugInfo)attributes;

                if (null != dbi) {
                    Console.WriteLine("バグ番号: {0}", dbi.BugNo);
                    Console.WriteLine("開発者: {0}", dbi.Developer);
                    Console.WriteLine("前回のレビュー日時: {0}", dbi.LastReview);
                    Console.WriteLine("コメント: {0}", dbi.Message);
                }
            }

            // メソッドの属性をループする
            foreach (MethodInfo m in type.GetMethods()) {
                foreach (Attribute a in m.GetCustomAttributes(true)) {
                    DeBugInfo dbi = (DeBugInfo)a;

                    if (null != dbi) {
                        Console.WriteLine("バグ番号: {0}, 関数名: {1}", dbi.BugNo, m.Name);
                        Console.WriteLine("開発者: {0}", dbi.Developer);
                        Console.WriteLine("前回のレビュー日時: {0}", dbi.LastReview);
                        Console.WriteLine("コメント: {0}", dbi.Message);
                    }
                }
            }
            Console.ReadLine();
        }
    }
}