C# リフレクションを理解する前に、いくつかの概念を理解する必要があります。
アセンブリ (アセンブリ)アセンブリはコンパイラによって取得され、CLR によるさらなるコンパイルのための中間生成物として提供されます。Windows システムでは、通常、次のような .dll (ライブラリ ファイル) および .exe (実行可能ファイル) として表示されます。
メタデータ (Metadata)一般に、メタデータとはデータを説明するためのデータのことで、プログラム内のクラス、クラス内の関数、変数などがプログラムのメタデータであり、アセンブリにはメタデータが格納されます。
これら 2 つの概念を理解すると、リフレクションとは何なのかを少し理解できるようになります。
プログラムの実行中、プログラムは他のアセンブリまたは自身のメタデータを表示できます。実行中のプログラムが自身または他のプログラムのメタデータを表示する動作は、リフレクションと呼ばれます。
では、C# ではリフレクションはどのように実装されるのでしょうか?
C # は、リフレクションの基礎となるクラスの情報クラスとみなすことができる特別なクラス Type を提供します。Type を使用して、型のメンバー (コンストラクター、メソッド、フィールド、属性など) に移動できます。、およびクラス属性) イベント)
Type を取得するには 3 つの方法があります。
1. オブジェクト基本クラスの GetType メソッドを呼び出して Type を取得します。
int a = 42;
Type type = a.GetType();
Console.WriteLine(type);
2. typeof キーワードを介してクラス名を渡します (最も一般的に使用されます)
Type type2 = typeof(int);
Console.WriteLine(type2);
3. クラス名で取得します。
Type type3 = Type.GetType("System.Int32");
Console.WriteLine(type3);
上記の 3 行のコードはすべて、この情報(Type タイプの名前)を出力します。
Type タイプを取得した後、そのタイプが配置されているアセンブリの情報を取得できます。
Console.WriteLine(type.Assembly);
Console.WriteLine(type2.Assembly);
Console.WriteLine(type3.Assembly);
同様に、3 行のコードは同じ情報、つまり int 型が配置されているアセンブリの情報を出力します。
続けて、Type 型を取得したので、クラス内のすべてのパブリック メンバーも取得できます。
1. クラスのコンストラクターを取得して呼び出します。
//1.获取所有的公共构造函数
ConstructorInfo[] ctors = t.GetConstructors();
for (int i = 0; i < ctors.Length; i++)
{
Console.WriteLine(ctors[i]);
}
//2.获取其中一个构造函数 并执行
//得构造函数 Type数组 数组中内容按顺序是 构造函数的参数类型
//执行构造函数传入 object数组 表示按顺序传入参数内容
//2-1 得到无参构造
ConstructorInfo info = t.GetConstructor(new Type[0]);
//执行无参构造
Test obj = info.Invoke(null) as Test;
Console.WriteLine(obj.j);
//2-2 得到有参构造
ConstructorInfo info2 = t.GetConstructor(new Type[] { typeof(int) });
obj = info2.Invoke(new object[] { 2 }) as Test;
Console.WriteLine(obj.str);
ConstructorInfo info3 = t.GetConstructor(new Type[] { typeof(int), typeof(string) });
obj = info3.Invoke(new object[] { 2, "反射捏" }) as Test;
Console.WriteLine(obj.j+obj.str);
Console.WriteLine("------------------------------------");
2.クラスのパブリック変数メンバーを取得します。
//1.得到所有的成员变量
FieldInfo[] fieldInfo = t.GetFields();
for (int i = 0; i < fieldInfo.Length; i++)
{
Console.WriteLine(fieldInfo[i]);
}
//2.得到指定名称的公共成员变量
FieldInfo infoJ = t.GetField("j");
Console.WriteLine(infoJ);
//3.通过反射 获取和设置对象的值
Test test = new Test();
test.j = 99;
test.str = "222";
//3-1 通过反射 获取对象的某个变量的值
Console.WriteLine(infoJ.GetValue(test));
//3-2 通过反射 设置指定对象的某个变量的值
infoJ.SetValue(test,101);
Console.WriteLine(infoJ.GetValue(test));
3. クラス内のパブリック メンバー メソッドを取得します。
//通过Type类中的GetMethod方法得到类中的方法
// MethodInfo 是方法的反射信息
Console.WriteLine("-----------------------------------");
Type strType = typeof(string);
MethodInfo[] methodInfos = strType.GetMethods();
for (int i = 0; i < methodInfos.Length; i++)
{
Console.WriteLine(methodInfos[i]);
}
//1.如果方法存在重载 用Type数组表示参数类型
MethodInfo methodInfo =strType.GetMethod("Substring",new Type[]{ typeof(int),typeof(int) });
//2.调用该方法
string str = "Kojima Hedio";
//第一个参数 是相当于那个对象要执行这个成员方法
object result = methodInfo.Invoke(str, new object[] { 0, 6 });
Console.WriteLine(result);
//注意:如果是静态方法 Invoke中的第一个参数传入null即可
上に型が配置されているアセンブリを取得しましたが、その本質もアセンブリ クラスであり、その主な目的は他のアセンブリを読み込んで、Type を使用して他のアセンブリの情報を使用できるようにすることです。自分のものではないアセンブリを使用する場合は、まずアセンブリをロードする必要があります。C# には、アセンブリを読み込む 3 つの方法が用意されています。
//一般用来加载在同一文件下的其它程序集
Assembly asembly2 = Assembly.Load("程序集名称");
//一般用来加载不在同一文件下的其它程序集
Assembly asembly = Assembly.LoadFrom("包含程序集清单的文件的名称或路径");
Assembly asembly3 = Assembly.LoadFile("要加载的文件的完全限定路径");
他のアセンブリを取得した後、次のようなさまざまなリフレクション操作を実行します。
//1.先加载一个指定的程序集
Assembly assembly = Assembly.LoadFrom(@"C:\Users\墨晴轩\source\repos\多线程练习\bin\Debug\net5.0\多线程练习");
Type[] types = assembly.GetTypes();
Console.WriteLine("-----------------------------------");
for (int i = 0; i < types.Length; i++)
{
Console.WriteLine(types[i]);
}
//2.在加载程序集中的一个类对象 之后才能使用反射
Type icon = assembly.GetType("多线程练习.Icon");
MemberInfo[] memberInfos = icon.GetMembers();
for (int i = 0; i < memberInfos.Length; i++)
{
Console.WriteLine(memberInfos[i]);
}
//通过反射实例化一个 icon 对象
//首先得到枚举Type 得到可以传入的参数
Type moveDir = assembly.GetType("多线程练习.E_MoveDir");
FieldInfo right = moveDir.GetField("Right");
//实例化对象
object iconObj = Activator.CreateInstance(icon, 10, 5, right);
//通过反射得到对象中的方法
MethodInfo move = icon.GetMethod("Move");
MethodInfo draw = icon.GetMethod("Draw");
MethodInfo clear = icon.GetMethod("Clear");
Console.Clear();
while (true)
{
Thread.Sleep(1000);
clear.Invoke(iconObj, null);
move.Invoke(iconObj, null);
draw.Invoke(iconObj, null);
}
上記のコードでは、Type によってオブジェクトをインスタンス化します。C# では、リフレクションで迅速に作成するためのクラスActivatorも提供していることがわかります。
//用于快速实例化对象的类
// 用于将Type 对象快捷实例化为对象
//先得到Type
//然后 快速实例化一个对象
Type testType = typeof(Test);
//1.无参构造
Test testObj = Activator.CreateInstance(testType) as Test ;
Console.WriteLine(testObj.str);
//有参构造
testObj = Activator.CreateInstance(testType, 99) as Test;
testObj = Activator.CreateInstance(testType, 99, "123123") as Test;