I Definition of reflection
The ability to review metadata and collect information about its types.
II Basic concepts
(1) Assembly: defines and loads an assembly, loads all modules in the assembly, finds a type from this assembly, and creates an instance of that type.
(2) Module: get the assembly containing the module and the classes in the module. You can also get all global methods or other specific non global methods defined on the module.
(3) ConstructorInfo: get the name, parameters, access modifiers (such as pulic or private) and implementation details (such as abstract or virtual) of the constructor.
(4) MethodInfo(GetMethod/GetMethods): get the name, return type, parameter, access modifier (such as pulic or private) and implementation details (such as abstract or virtual) of the method.
(5) Fieldinfo (getfield / getfields): get the field name, access modifier (such as public or private) and implementation details (such as static), and get or set the field value.
(6) EventInfo(GetEvent/GetEvents): get the event name, event handler data type, custom attribute, declaration type and reflection type, and add or remove event handlers.
(7) PropertyInfo(GetProperty/GetProperties): get the name, data type, declaration type, reflection type and read-only or writable state of the property, and get or set the property value.
(8) ParameterInfo: get the name, data type, input parameter or output parameter of the parameter, and the position of the parameter in the method signature.
(9) MemberInfo(GetMember/GetMembers): get fields, events, properties and other information
III Reflex action
Before demonstrating the role of reflection, we first define the following entity class, assuming that the entity class is located under a third-party class library, the class library name is "TestClass" and the class name is "Person"
public class Person { private int id; public int Id { get => id; set => id = value; } public string Name { set; get; } public string Phone { get; set; } public Person() { } public Person(string a, int b) { this.Name = a; this.Phone = b.ToString(); } public Person(int id, string name, string phone) { this.Id = id; this.Name = name; this.Phone = phone; } public string getName() { return this.Name; } public string getName1(string str) { return str; } public string getPhone() { return this.Phone; } public string getPhone(string str) { return this.Phone+str; } public string getPhone(string str,int num) { return this.Phone + str+num; } private void privateMethod(string a) { Console.WriteLine("This is a private method,The parameters passed in are:"+a); } }
1. Create an object without parameters
The essence of creating an object without maturity is to call a parameterless constructor. The specific implementation is as follows
/// <summary> ///Create an object without parameters /// </summary> /// <returns></returns> private static Person CreateWithoutParms() { Assembly assembly = Assembly.Load("TestClass");//Load assembly Type type = assembly.GetType("TestClass.Person");//Get class name (with namespace) object o = Activator.CreateInstance(type);//Create a Person entity without parameters Person person = o as Person; return person; }
Call in console
The returned results are as follows:Person person = CreateWithoutParms(); person.Name = "Zhang San"; Console.WriteLine("person.Name:"+ person.Name);

Successfully called and created Person, and called the parameterless constructor of Person
2. Create an object with parameters
The essence of creating a mature object is to call the constructor with parameters. The specific implementation is as follows
/// <summary> ///Creating objects with parameters /// </summary> /// <returns></returns> private static Person CreateWithParms() { Assembly assembly = Assembly.Load("TestClass");//Load assembly Type type = assembly.GetType("TestClass.Person");//Get class name (with namespace) object o = Activator.CreateInstance(type, new object[] {"a",666 });//Create a Person entity with parameters Person person = o as Person; return person; }
Call in console
The returned results are as follows:Person person = CreateWithParms(); Console.WriteLine("person.Name:"+person.Name+ " person.Phone:" + person.Phone);

Successfully called, created Person, and directly assigned value to the attribute by using the construction with parameters
####Note: if the constructor is private, you can set the nonPublic parameter in CreateInstance to true when creating an instance to create an instance using the private constructor
object o = Activator.CreateInstance(type,true);
3. Call public methods
Using reflection to call the methods of the third-party class, you can use the obtained object to execute the methods in the object after obtaining the corresponding object through reflection. However, here, we mainly explain how to directly call the methods in the third-party class through reflection. The specific implementation is as follows
/// <summary> ///Calling a method with parameters (no overloading) /// </summary> /// <returns></returns> private static string CallFunction() { Assembly assembly= Assembly.Load("TestClass"); Type type = assembly.GetType("TestClass.Person"); object o = Activator.CreateInstance(type); MethodInfo methodInfo = type.GetMethod("getName1"); string result=methodInfo.Invoke(o, new object[] { "This is an incoming parameter" }).ToString(); return result; }
Call in console
The returned results are as follows:string rsult = CallFunction(); Console.WriteLine(rsult);

Here we see that getName1 method is successfully called by reflection. It should be noted that getName1 method does not have any overload. If you need to call a method with overload, you need to use the following method. Here we assume that you need to call getPhone(string str,int num) method
private static string CallFunctionWithOverload() { Assembly assembly = Assembly.Load("TestClass"); Type type = assembly.GetType("TestClass.Person"); object o = Activator.CreateInstance(type); MethodInfo methodInfo = type.GetMethod("getPhone", new Type[] { typeof(string), typeof(int) });//Here, you need to pass the parameter type array to the GetMethod method string result=methodInfo.Invoke(o, new object[] { "This is incoming String parameter", 666 }).ToString(); return result; }
Call in console
The returned results are as follows:string rsult = CallFunctionWithOverload(); Console.WriteLine(rsult);

Through the above examples, we can see that the key to calling overloaded and non overloaded methods is whether to pass the type of parameters in GetMethod.
The following is a comprehensive example to call all methods in the Person class and output the results. If the parameter type is String, it will be passed to "AAA" by default. If the parameter type is Int, it will be passed to 666 by default. The implementation method is as follows:
private static void CallAllFunction() { Assembly assembly = Assembly.Load("TestClass"); Type type = assembly.GetType("TestClass.Person"); object o = Activator.CreateInstance(type); foreach (MethodInfo methodInfoItem in type.GetMethods()) { Console.WriteLine("implement"+ methodInfoItem.Name+ "method"); List<object> objectList = new List<object>(); foreach (ParameterInfo parameterInfoItem in methodInfoItem.GetParameters()) { if (parameterInfoItem.ParameterType == typeof(String)) { objectList.Add("AAA"); } else if (parameterInfoItem.ParameterType == typeof(int)) { objectList.Add(666); } } try//Try is used here catch... This is to simplify the processing of program error caused by property acquisition failure { string result = methodInfoItem.Invoke(o, objectList.ToArray()).ToString(); Console.WriteLine("The result is:" + result); } catch { } } }
The returned results after calling are as follows:

Here we see that all the methods in Person have been executed, including all system methods
4. Call private method
The returned results after calling are as follows:/// <summary> ///Call private method /// </summary> private static void CallPrivateFunction() { Assembly assembly = Assembly.Load("TestClass"); Type type = assembly.GetType("TestClass.Person"); object o = Activator.CreateInstance(type); MethodInfo methodInfo = type.GetMethod("privateMethod", BindingFlags.Instance | BindingFlags.NonPublic); methodInfo.Invoke(o, new object[] { "Zhang San"}); }

Through the above examples, it is not difficult to find that the difference between calling public methods and private methods is whether "BindingFlags.Instance | BindingFlags.NonPublic" is set when calling the GetMethod method of type
5. Get and operate attributes
The returned results after calling are as follows:/// <summary> ///Get and action properties /// </summary> /// <param name="propertyName"></param> /// <param name="propertyValue"></param> private static void getAndSetProperity(string propertyName,string propertyValue) { //1. Create Person entity through reflection Assembly assembly = Assembly.Load("TestClass"); Type type = assembly.GetType("TestClass.Person"); object o = Activator.CreateInstance(type, new object[] { "Zhang San", 131000000 }); PropertyInfo propertyInfo=type.GetProperty(propertyName); Console.WriteLine("Before modification Phone: "+ propertyInfo.GetValue(o));//Get property value propertyInfo.SetValue(o, propertyValue);//Set attribute value Console.WriteLine("After modification Phone: " + propertyInfo.GetValue(o)); }

Through the above examples, it can be found that the key methods to obtain and set properties are GetValue and SetValue respectively, and the key incoming parameters are entity classes obtained through reflection
6. Get and operate fields
The returned results after calling are as follows:/// <summary> ///Get and action fields /// </summary> /// <param name="fieldName"></param> /// <param name="fieldValue"></param> private static void getAndSetField(string fieldName, int fieldValue) { Assembly assembly = Assembly.Load("TestClass"); Type type = assembly.GetType("TestClass.Person"); object o = Activator.CreateInstance(type, new object[] {1, "Zhang San", "131000000" }); FieldInfo fieldInfo = type.GetField(fieldName, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance); Console.WriteLine("Before modification id"+ fieldInfo.GetValue(o)); fieldInfo.SetValue(o, fieldValue); Console.WriteLine("After modification id" + fieldInfo.GetValue(o)); }

The method of setting and operating fields is basically the same as that of setting and operating properties. It should be noted that when using the GetField method of type, if you get or set a private field, you need to set the accessible property of the method. In this example, it is set to "BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance"
Next, we will continue to study the role of reflection in generics. Before further research, we will first define the following generic class. Like the above entity class, suppose that the generic class is located under a third-party class library with the name of "TestClass" and the class name of "GenericClass"
public class GenericClass<X,Y,Z> { public X xxx{ set; get; } public Y yyy { set; get; } public Z zzz { set; get; } public void PrintParm<A,B,C>(A a, B b, C c) { Console.WriteLine("A The type of is" + a.GetType().Name + ",Value is" + a.ToString()); Console.WriteLine("B The type of is" + b.GetType().Name + ",Value is" + b.ToString()); Console.WriteLine("C The type of is" + c.GetType().Name + ",Value is" + c.ToString()); } }
7. Create a generic class and call
The returned results after calling are as follows:/// <summary> ///Calling a method in a generic class /// </summary> private static void GenericWithParms() { Assembly assembly = Assembly.Load("TestClass"); Type type = assembly.GetType("TestClass.GenericClass`3"); type= type.MakeGenericType(new Type[] { typeof(string),typeof(int),typeof(DateTime)}); object o = Activator.CreateInstance(type); MethodInfo methodInfo = type.GetMethod("PrintParm"); methodInfo = methodInfo.MakeGenericMethod(new Type[] { typeof(string), typeof(int), typeof(DateTime) }); methodInfo.Invoke(o, new object[] {"Zhang San",666,DateTime.Now}); }

For the above codes, the following explanations are made:
1).
This setting is required only when creating a generic class. The number is the total number of parameters of the generic class
2).
Before creating a generic entity, set the passed in parameter type through the MakeGenericType method of type
3).
Just like creating a generic class, you need to set the parameter type of the generic method before calling the generic method
4). If you call a generic method in a generic class, you do not need to set the parameter type of the generic method. On the contrary, if you call a generic method in a generic class, you do not need to set the number of generic class parameters or the parameter type
So far, the common ways of reflection are explained