(2/∞) Reflection mechanism in C#

Before understanding C# reflection, you need to understand a few concepts

Assembly (Assembly) The assembly is obtained by the compiler and provided as an intermediate product for further compilation by the CLR. In Windows systems, it generally appears as .dll (library file) and .exe (executable file) similar to the following

 Metadata (Metadata) Generally speaking, metadata is the data used to describe data. The classes in the program, the functions in the class, variables, etc. are the metadata of the program, and the metadata is stored in the assembly.

After understanding these two concepts, you can understand a little bit what is reflection ?

When a program is running, it can view other assemblies or its own metadata. The behavior of a running program viewing its own or other program's metadata is called reflection.

So how is reflection implemented in C#?

C # provides a special class, Type, which can be regarded as the information class of the class, which is the basis of reflection. We can use Type to go to the members of the type (such as constructors, methods, fields, attributes, and class attributes) event)

There are three ways to get Type:

1. Get the Type by calling the GetType method in the Object base class

int a = 42;
Type type = a.GetType();
Console.WriteLine(type);

2. Pass in the class name through the typeof keyword (most commonly used)

Type type2 = typeof(int);
Console.WriteLine(type2);

3. Get it by the name of the class

Type type3 = Type.GetType("System.Int32");
Console.WriteLine(type3);

The above three lines of code all print out this information, the name of the Type type

After getting the Type type, you can get the information of the assembly where the type is located

Console.WriteLine(type.Assembly);
Console.WriteLine(type2.Assembly);
Console.WriteLine(type3.Assembly);

 Similarly, the three lines of code print out the same information, the information of the assembly where the int type is located

 Continue, now that we have the Type type, we can also get all the public members in the class

1. Get the constructor of the class and call it

            //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. Get the public variable members of the class

            //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. Get the public member methods in the class

            //通过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即可

We obtained the assembly where the type is located above, and its essence is also an assembly class. Its main purpose is to load other assemblies, so that Type can be used to use information in other assemblies. If you want to use an assembly that is not your own, you must first load the assembly. C# provides three methods of loading assemblies.

            //一般用来加载在同一文件下的其它程序集
            Assembly asembly2 = Assembly.Load("程序集名称");

            //一般用来加载不在同一文件下的其它程序集
            Assembly asembly = Assembly.LoadFrom("包含程序集清单的文件的名称或路径");
            Assembly asembly3 = Assembly.LoadFile("要加载的文件的完全限定路径"); 

After we have obtained other assemblies, perform various reflection operations such as the following:

            //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);
            }

In the above code, we instantiate an object by Type. It can be seen that C# also provides us with a class for quick creation in reflection, 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;

Guess you like

Origin blog.csdn.net/qq_52690206/article/details/127045297