1. Overview
1. Reflections provide type information that allows developers to construct and use objects at runtime
2. Reflection mechanism allows programs to dynamically add various functions during execution
Runtime Type Identification
1. Runtime Type Flag (RTTI), which can determine object type during program execution.For example, use his ability to know exactly what type of object the base class reference points to.
2. Runtime type identification, which can pre-test the success of a mandatory type conversion operation to avoid invalid mandatory type conversion exceptions.
3. There are three keywords supporting RTTI in C#: is, as, typeof.Introduce them next time
is operator:
The is operator allows you to determine if an object type is a specific type. If the two types are the same type, or if there is a reference between them, the boxing-unboxing conversion indicates that the two types are compatible.The code is as follows:
1 static void Main()
2 {
3 A a = new A();
4 B b = new B();
5 if (a is A)
6 {
7 Console.WriteLine("a is an A");
8 }
9
10 if (b is A)
11 {
12 Console.WriteLine("b is an A because it is derived from");
13 }
14
15 if (a is B)
16 {
17 Console.WriteLine("This won't display,because a not derived from B");
18 }
19
20 if (a is object)
21 {
22 Console.WriteLine("a is an object");
23 }
24 Console.ReadKey();
25 }
Result:
The as operator:
A null value is returned when a type conversion is performed at run time and can be failed without throwing an exception. As can also be considered as a simplified alternative to an is operator as follows:
1 static void Main()
2 {
3 A a = new A();
4 B b = new B();
5 if (a is B)
6 {
7 b = (B) a;//Because a Variable is not B Type, so here you will a Convert variable to B Invalid for type
8 }
9 else
10 {
11 b = null;
12 }
13
14 if (b==null)
15 {
16 Console.WriteLine("The cast in b=(B)a is not allowed");
17 }
18 //Use above as Operator, able to combine two parts into one
19 b = a as B;//as The operator first checks the validity of the type to which it is converted and, if so, executes the strong type conversion process, which is accomplished in this sentence
20 if (b==null)
21 {
22 Console.WriteLine("The cast in b=(B)a is not allowed");
23 }
24 Console.ReadKey();
25 }
Result:
The typeof operator:
as and is are capable of testing the compatibility of both types, but in most cases, specific information of one type is required.This uses typeof, which returns a System.Type object associated with a specific type, through which the characteristics of that type can be determined.Once you get a Type object of a given type, you can get specific information about the type by using the respective properties, fields, and methods defined by the object.The Type class contains many primitives, which are discussed in more detail in the next reflection.The following is a simple demonstration of a Type object that calls its three properties.
1 static void Main()
2 {
3 Type t = typeof(StringBuilder);
4 Console.WriteLine(t.FullName);//FullName Full name of property return type
5 if (t.IsClass)
6 {
7 Console.WriteLine("is a Class");
8 }
9
10 if (t.IsSealed)
11 {
12 Console.WriteLine("is Sealed");
13 }
14 Console.ReadKey();
15 }
Result:
3. Core type of reflection: System.Type class
1. Many of the types that support reflection are located in the System.Reflection namespace and are part of the.net Reflection API, so the system.Reflection namespace is typically used in reflex reuse programs.
2. The System.Type class wraps types and is therefore the core of the entire reflection subsystem. It contains many properties and methods that can be used to retrieve type information at runtime.
3. Type class derives from System.Reflection.MemberInfo abstract class
Read-only properties in the MemberInfo class |
|
attribute |
describe |
Type DeclaringType |
Gets the type of class or interface that declares the member |
MemberTypes MemberType |
Gets the type of member, which indicates that the member is a field, method, property, event, or constructor |
Int MetadataToken |
Getting values associated with specific metadata |
Module Module |
Gets a Modal object that represents the Module (executable) in which the reflection type is located |
String Name |
Name of member |
Type ReflectedType |
Reflected object type |
Please note that:
1. The return type of the MemberType property is MemberTypes, which is an enumeration that defines the information values used to represent different primitives, including MemberTypes.Constructor, MemeberTypes.Method, MemberTypes.Event, MemberTypes.Property.So you can determine the type of the primitive by checking the MemberType property, such as when the value of the MenberType property is MemberTypes.Method, the member is a method
2. The MemberInfo class also contains two abstract methods related to attributes:
(1) GetCustomAttributes(): Get a list of custom attributes related to the primary object.
(2) IsDefined(): Determines if the corresponding attributes are defined for the primary object.
(3) GetCustomeAttributesData(): Returns information about custom attributes (attributes will be mentioned later)
Of course, in addition to the methods and attributes defined by the MemberInfo class, the Type class also adds many attributes and methods: the following table (only a few commonly used, too many 20s are listed, so you can redefine the Type class yourself to see)
Method of Type Class Definition |
|
Method |
function |
ConstructorInfo[] GetConstructors() |
Gets a list of constructors of the specified type |
EventInfo[] GetEvents(); |
Gets the time column of the specified type |
FieldInfo[] GetFields(); |
Gets the field column of the specified type |
Type[] GetGenericArguments(); |
Gets a list of type parameters bound to a constructed generic type, and type parameters if a generic type definition of a specified type is specified.For types that are being constructed earlier, the list may contain both type arguments and type parameters |
MemberInfo[] GetMembers(); |
Gets the list of members of the specified type |
MethodInfo[] GetMethods(); |
Gets a list of methods of the specified type |
PropertyInfo[] GetProperties(); |
Gets a list of properties of the specified type |
Common read-only properties for Type type definitions are listed below
Properties defined by Type class |
|
attribute |
function |
Assembly Assembly |
Gets the assembly of the specified type |
TypeAttributes Attributes |
Get the attributes of the formulation type |
Type BaseType |
Gets the direct base type of the specified type |
String FullName |
Gets the full name of the specified type |
bool IsAbstract |
Returns true if the specified type is abstract |
bool IsClass |
Returns true if the specified type is a class |
string Namespace |
Gets the namespace of the specified type |
4. Use reflection
All of these will be padded with reflections.
By using the methods and properties defined by the Type class, we can get a variety of specific information about the type at run time.This is a very powerful feature, once we get the type information, we can call its constructors, methods, properties, and you can see that reflection allows you to use code that is not available at compile time.
Because there are so many Feflection API s, it is impossible to fully introduce them here (here, if a full introduction, it is said to require a book, a thick book).However, the Reflection API is designed according to some logic, so as long as you know how some interfaces are used, you can use the remaining interfaces one after another.
Here I list four key reflection techniques:
1. Getting information about methods
2. Call Method
3. Constructing Objects
4. Loading types from assemblies
5. Information on acquisition methods
Once you have a Type object, you can use the GetMethodInfo() method to get a list of all the methods supported by this type.This method returns an array of MethodInfo objects that represent the methods supported by the primary type, which are located in the System.Reflection namespace.The MethodInfo class derives from the MethodBase Abstract class, which inherits the MemberInfo class, so we can use these three types of defined properties and methods.For example, using the Name property to the method name, there are two important members:
1. ReturnType property: An object of type Type that provides information about the return type of the method.
2. GetParameters() method: Returns a list of parameters, and the parameter information is stored as an array in the PatameterInfo object.The PatameterInfo class defines a number of attributes and methods that represent parameter information, and two common attributes have come up here: Name (a string containing parameter name information), and ParameterType (information about parameter type).
The following code will use reflection to get the supported methods in the class, along with information about the methods:
1 class Program
2 {
3 static void Main()
4 {
5 //Get Description MyClass Type Type object
6 Type t = typeof(MyClass);
7 Console.WriteLine($"Analyzing methods in {t.Name}");
8 //MethodInfo Object in System.Reflection Under Namespace
9 MethodInfo[] mi = t.GetMethods();
10 foreach (var methodInfo in mi)
11 {
12 //Return type of return method
13 Console.Write(methodInfo.ReturnType.Name);
14 //Return the name of the method
15 Console.Write($" {methodInfo.Name} (");
16 //Get the method description list and save it in ParameterInfo In object group
17 ParameterInfo[] pi = methodInfo.GetParameters();
18 for (int i = 0; i < pi.Length; i++)
19 {
20 //Parameter Type Name of Method
21 Console.Write(pi[i].ParameterType.Name);
22 //Parameter name of method
23 Console.Write($" {pi[i].Name}");
24 if (i+1<pi.Length)
25 {
26 Console.Write(", ");
27 }
28 }
29
30 Console.Write(")");
31 Console.Write("\r\n");
32 Console.WriteLine("--------------------------");
33 }
34 Console.ReadKey();
35 }
36 }
37
38 class MyClass
39 {
40 private int x;
41 private int y;
42
43 public MyClass()
44 {
45 x = 1;
46 y = 1;
47 }
48
49 public int Sum()
50 {
51 return x + y;
52 }
53
54 public bool IsBetween(int i)
55 {
56 if (x < i && i < y)
57 {
58 return true;
59 }
60
61 return false;
62 }
63
64 public void Set(int a, int b)
65 {
66 x = a;
67 y = b;
68 }
69
70 public void Set(double a, double b)
71 {
72 x = (int)a;
73 y = (int)b;
74 }
75
76 public void Show()
77 {
78 System.Console.WriteLine($"x:{x},y:{y}");
79 }
80 }
Output results:
Note: In addition to all the methods defined by the MyClass class, the output here also shows the common non-static methods defined by the object class.This is because all types in C#inherit from the Object class.In addition, this information is obtained dynamically while the program is running, and you do not need to know the definition of the MyClass class
Another form of the GetMethods() method
This form specifies various tags and filters the method you want to get. Its common form is: MethodInfo[] GetMethods(BindingFlags bindingAttr)
BindingFlags is an enumeration with a number of values (many, here are only five commonly used)
(1) DeclareOnly: Get only the method defined by the specified class, not the inherited method
(2) Instance: Get Instance Method
(3) NonPublic: Get non-public methods
(4) Public: Get Common Methods
(5) Static: Getting static methods
GetMethods(BindingFlags bindingAttr) is a method in which a parameter can use or to join two or more tags together, essentially at least Instance (or Static) and Public (or NonPublic) tags, or else no method will be obtained.Let's write an example to demonstrate.
1 class Program
2 {
3 static void Main()
4 {
5 //Get Description MyClass Type Type object
6 Type t = typeof(MyClass);
7 Console.WriteLine($"Analyzing methods in {t.Name}");
8 //MethodInfo Object in System.Reflection Under Namespace
9 //Do not get inheritance method, it is instance method,·For Public
10 MethodInfo[] mi = t.GetMethods(BindingFlags.DeclaredOnly|BindingFlags.Instance|BindingFlags.Public);
11 foreach (var methodInfo in mi)
12 {
13 //Return type of return method
14 Console.Write(methodInfo.ReturnType.Name);
15 //Return the name of the method
16 Console.Write($" {methodInfo.Name} (");
17 //Get the method description list and save it in ParameterInfo In object group
18 ParameterInfo[] pi = methodInfo.GetParameters();
19 for (int i = 0; i < pi.Length; i++)
20 {
21 //Parameter Type Name of Method
22 Console.Write(pi[i].ParameterType.Name);
23 //Parameter name of method
24 Console.Write($" {pi[i].Name}");
25 if (i+1<pi.Length)
26 {
27 Console.Write(", ");
28 }
29 }
30
31 Console.Write(")");
32 Console.Write("\r\n");
33 Console.WriteLine("--------------------------");
34 }
35 Console.ReadKey();
36 }
37 }
38
39 class MyClass
40 {
41 private int x;
42 private int y;
43
44 public MyClass()
45 {
46 x = 1;
47 y = 1;
48 }
49
50 public int Sum()
51 {
52 return x + y;
53 }
54
55 public bool IsBetween(int i)
56 {
57 if (x < i && i < y)
58 {
59 return true;
60 }
61
62 return false;
63 }
64
65 public void Set(int a, int b)
66 {
67 x = a;
68 y = b;
69 }
70
71 public void Set(double a, double b)
72 {
73 x = (int)a;
74 y = (int)b;
75 }
76
77 public void Show()
78 {
79 System.Console.WriteLine($"x:{x},y:{y}");
80 }
81 }
Output results:
As you can see from the example above, only the methods defined by the MyClass class are shown, and private int Sum() is not.
6. Calling methods using reflection
Above we get all the information in the class by reflection, and below we call the method by reflection.To invoke the method obtained by reflection, you need to invoke the Invoke() method on the MethodInfo instance, using Invoke(), as illustrated in the following example:
The following example first obtains the method to be invoked through reflection, then uses the Invoke() method to invoke the specified method obtained:
1 class Program
2 {
3 static void Main()
4 {
5 //Get Description MyClass Type Type object
6 Type t = typeof(MyClass);
7 MyClass reflectObj = new MyClass();
8 reflectObj.Show();
9 //Do not get inheritance method, it is instance method,·For Public
10 MethodInfo[] mi = t.GetMethods(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public);
11 foreach (var methodInfo in mi)
12 {
13
14 //Get the method description list and save it in ParameterInfo In object group
15 ParameterInfo[] pi = methodInfo.GetParameters();
16 if (methodInfo.Name.Equals("Set", StringComparison.Ordinal) && pi[0].ParameterType == typeof(int))
17 {
18 object[] args = new object[2];
19 args[0] = 9;
20 args[1] = 10;
21 methodInfo.Invoke(reflectObj,args);
22 }
23 }
24 Console.ReadKey();
25 }
26 }
27
28 class MyClass
29 {
30 private int x;
31 private int y;
32
33 public MyClass()
34 {
35 x = 1;
36 y = 1;
37 }
38
39 public int Sum()
40 {
41 return x + y;
42 }
43
44 public bool IsBetween(int i)
45 {
46 if (x < i && i < y)
47 {
48 return true;
49 }
50
51 return false;
52 }
53
54 public void Set(int a, int b)
55 {
56 x = a;
57 y = b;
58 Show();
59 }
60
61 private void Set(double a, double b)
62 {
63 x = (int)a;
64 y = (int)b;
65 }
66
67 public void Show()
68 {
69 System.Console.WriteLine($"x:{x},y:{y}");
70 }
71 }
Gets the constructor for the Type object
In the previous discussion, since objects of type MyClass are all created by display, there is no advantage in using reflection technology to invoke methods in MyClass classes, rather than simply calling them in a normal way. However, if objects are created dynamically at runtime, the advantage of reflection will become apparent.In this case, you first get a list of constructors, then call a constructor in the list to create an instance of that type, which allows you to instantiate any type of object at run time without specifying a type in the declaration statement.
The sample code is as follows:
1 class Program
2 {
3 static void Main()
4 {
5 //Get Description MyClass Type Type object
6 Type t = typeof(MyClass);
7 int val;
8 //Use this method to get a list of constructors
9 ConstructorInfo[] ci = t.GetConstructors();
10 int x;
11 for (x = 0; x < ci.Length; x++)
12 {
13 //Gets the list of constructor parameters when
14 ParameterInfo[] pi = ci[x].GetParameters();
15 if (pi.Length == 2)
16 {
17 //Jump out of the loop if the current constructor has two parameters
18 break;
19 }
20 }
21
22 if (x == ci.Length)
23 {
24 return;
25 }
26 object[] consArgs = new object[2];
27 consArgs[0] = 10;
28 consArgs[1] = 20;
29 //Instantiates a type object with several arguments to this constructor, if the argument is empty null
30
31 object reflectOb = ci[x].Invoke(consArgs);
32
33 MethodInfo[] mi = t.GetMethods(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public);
34 foreach (var methodInfo in mi)
35 {
36 if (methodInfo.Name.Equals("Sum", StringComparison.Ordinal))
37 {
38 val = (int)methodInfo.Invoke(reflectOb, null);
39 Console.WriteLine($"Sum is {val}");
40 }
41 }
42 Console.ReadKey();
43 }
44 }
45
46 class MyClass
47 {
48 private int x;
49 private int y;
50
51 public MyClass(int i)
52 {
53 x = y + i;
54 }
55
56 public MyClass(int i, int j)
57 {
58 x = i;
59 y = j;
60 }
61
62 public int Sum()
63 {
64 return x + y;
65 }
66 }
Output results:
7. Obtaining types from assemblies
It can be seen in the previous explanations that all the information of a type can be reflected, but the MyClass type itself is not. Although the previous explanations can dynamically determine the information of the MyClass class, they are based on the fact that the type name is known beforehand and used in typeof and plays to get the Type object.Although this may work in many cases, to fully utilize reflection, we also need to analyze the contents of the reflection assembly to dynamically determine the available types of programs.
With the Reflection API, assemblies can be loaded, information about them can be obtained, and instances of their publicly available types can be created, through which a program can search its environment and take advantage of potential functionality without having to define them as they appear during compilation. This is a very effective and exciting concept.To illustrate how to get the types in an assembly, I created two files, the first defining a set of classes and the second reflecting information of each type.The effect of the code is as follows:
1. Compile the following code to generate the MyTest2_C.exe file
1 class Program
2 {
3 static void Main(string[] args)
4 {
5 Console.WriteLine("Hello word !");
6 Console.ReadKey();
7 }
8 }
9
10 class MyClass
11 {
12 private int x;
13 private int y;
14
15 public MyClass(int i)
16 {
17 x = y + i;
18 }
19
20 public MyClass(int i, int j)
21 {
22 x = i;
23 y = j;
24 }
25
26 public int Sum()
27 {
28 return x + y;
29 }
30 }
2. Get the above generated assembly's
1 class Program
2 {
3 static void Main()
4 {
5 //Load the specified assembly
6 Assembly asm = Assembly.LoadFrom(@"E:\Own\MyTest\MyTest2_C\bin\Debug\MyTest2_C.exe");
7 //Gets a list of all types in an assembly
8 Type[] allType = asm.GetTypes();
9 foreach (var type in allType)
10 {
11 //Print out type name
12 Console.WriteLine(type.Name);
13 }
14
15 Console.ReadKey();
16 }
17 }
Output results:
The type in the assembly is obtained above, and if you manipulate a method in an assembly type, you can do the same as the method we described earlier.
Okay,.Net Reflection, that's where we're going~