工業製造
産業用モノのインターネット | 工業材料 | 機器のメンテナンスと修理 | 産業プログラミング |
home  MfgRobots >> 工業製造 >  >> Industrial programming >> C言語

C#リフレクション:実行時型情報取得と動的プログラミング

リフレクション(Reflection)オブジェクトは、実行時に型情報を取得するために使用されます。実行中のプログラムのメタデータにアクセスするクラスはSystem.Reflection名前空間にあります。

System.Reflection名前空間には、アプリケーションについての情報を取得し、型、値、オブジェクトを動的にアプリケーションに追加するクラスが含まれています。

リフレクションの用途

メタデータの表示

前章で説明したように、リフレクションを使用して属性情報を表示できます。

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 {
        get => topic;
        set => topic = value;
    }
    public HelpAttribute(string url) {
        this.Url = url;
    }
    private string topic;
}

[HelpAttribute("Information on the class MyClass")]
class MyClass { }

namespace AttributeAppl {
    class Program {
        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属性の読み取り

前章で作成したDeBugInfo属性を使用し、リフレクションでRectangleクラスのメタデータを読み取ります。

using System;
using System.Reflection;

namespace BugFixApplication {
    [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) {
            bugNo = bg; developer = dev; lastReview = d;
        }
        
        public int BugNo => bugNo;
        public string Developer => developer;
        public string LastReview => lastReview;
        public string Message { get => message; set => message = value; }
    }
    
    [DeBugInfo(45, "Zara Ali", "12/8/2012", Message = "Return type mismatch")]
    [DeBugInfo(49, "Nuha Ali", "10/10/2012", Message = "Unused variable")]
    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 = "Return type mismatch")]
        public double GetArea() => length * width;
        
        [DeBugInfo(56, "Zara Ali", "19/10/2012")]
        public void Display() {
            Console.WriteLine("Length: {0}", length);
            Console.WriteLine("Width: {0}", width);
            Console.WriteLine("Area: {0}", GetArea());
        }
    }
    
    class ExecuteRectangle {
        static void Main(string[] args) {
            Rectangle r = new Rectangle(4.5, 7.5);
            r.Display();
            
            Type type = typeof(Rectangle);
            
            // クラスレベルの属性を取得
            foreach (object attr in type.GetCustomAttributes(false)) {
                if (attr is DeBugInfo dbi) {
                    Console.WriteLine("Bug No: {0}", dbi.BugNo);
                    Console.WriteLine("Developer: {0}", dbi.Developer);
                    Console.WriteLine("Last Reviewed: {0}", dbi.LastReview);
                    Console.WriteLine("Remarks: {0}", dbi.Message);
                }
            }
            
            // メソッドレベルの属性を取得
            foreach (MethodInfo m in type.GetMethods()) {
                foreach (Attribute a in m.GetCustomAttributes(true)) {
                    if (a is DeBugInfo dbi) {
                        Console.WriteLine("Bug No: {0}, for Method: {1}", dbi.BugNo, m.Name);
                        Console.WriteLine("Developer: {0}", dbi.Developer);
                        Console.WriteLine("Last Reviewed: {0}", dbi.LastReview);
                        Console.WriteLine("Remarks: {0}", dbi.Message);
                    }
                }
            }
            Console.ReadLine();
        }
    }
}

実行結果:

Length: 4.5
Width: 7.5
Area: 33.75
Bug No: 49
Developer: Nuha Ali
Last Reviewed: 10/10/2012
Remarks: Unused variable
Bug No: 45
Developer: Zara Ali
Last Reviewed: 12/8/2012
Remarks: Return type mismatch
Bug No: 55, for Method: GetArea
Developer: Zara Ali
Last Reviewed: 19/10/2012
Remarks: Return type mismatch
Bug No: 56, for Method: Display
Developer: Zara Ali
Last Reviewed: 19/10/2012
Remarks: 

リフレクションの主要API

Typeクラス(型情報のエントリポイント)

プロパティ/メソッド説明
typeof(T) / obj.GetType()Typeオブジェクトを取得
Name / FullName / Namespace型名情報
Assembly所属アセンブリ
BaseType基底型
GetInterfaces()実装インターフェース配列
IsClass/IsInterface/IsValueType/IsAbstract/IsSealed型種別判定
GetMembers()すべてのメンバー取得
GetMethods()/GetProperties()/GetFields()/GetConstructors()各種メンバー取得
GetCustomAttributes()属性取得
CreateInstance()インスタンス生成(遅延バインディング)

動的インスタンス生成とメソッド呼び出し

Type type = typeof(MyClass);
object instance = Activator.CreateInstance(type);  // デフォルトコンストラクタ

// パラメータ付きコンストラクタ
object instance2 = Activator.CreateInstance(type, arg1, arg2);

// メソッド呼び出し
MethodInfo method = type.GetMethod("MyMethod");
object result = method.Invoke(instance, new object[] { arg1, arg2 });

// プロパティ設定/取得
PropertyInfo prop = type.GetProperty("MyProperty");
prop.SetValue(instance, "New Value");
object value = prop.GetValue(instance);

アセンブリ操作


// 現在のアセンブリ
Assembly asm = Assembly.GetExecutingAssembly();

// ファイルからロード
Assembly asm2 = Assembly.LoadFrom("MyLibrary.dll");

// アセンブリ内のすべての型を取得
Type[] types = asm.GetTypes();

// 特定の型を取得
Type t = asm.GetType("MyNamespace.MyClass");

式木(Expression Trees)と動的コード生成

リフレクションのさらに高度な用途として、実行時にコードを生成・コンパイル・実行できます。

using System.Linq.Expressions;

// x => x + 1 というラムダ式を式木として構築
ParameterExpression x = Expression.Parameter(typeof(int), "x");
Expression> lambda = Expression.Lambda>(
    Expression.Add(x, Expression.Constant(1)), x
);

// コンパイルしてデリゲートとして実行
Func compiled = lambda.Compile();
int result = compiled(5);  // 6

パフォーマンス考慮事項

よくあるユースケース

ベストプラクティス

C言語

  1. C# Hello World – 初めてのC#アプリケーション構築
  2. C# キーワードと識別子:ルール、一覧、ベストプラクティス完全ガイド
  3. C# 変数とプリミティブデータ型:完全マスターガイド
  4. C#演算子完全ガイド:C#における演算子の包括的解説
  5. C# ビット演算子とビットシフト演算子をマスターする:包括的ガイド
  6. C# 入出力の基礎:ユーザー入力と出力の基本をマスター
  7. C# の式、文、ブロック:実践例で徹底理解
  8. C# コメントをマスターする:種類、ベストプラクティス、XML ドキュメント
  9. C# break 文:使い方とタイミングを徹底解説
  10. C# continue 文をマスターする:ループ反復を効果的にスキップする方法
  11. C# 配列をマスターする:宣言、初期化、操作