Reflection definition: the ability to review metadata and collect information about its type. Metadata (the most basic data unit after compilation) is a lot of tables. When compiling an assembly or module, the compiler creates a class definition table and a field definition table, and a method definition table.
Function of reflection:
1. You can use reflection to dynamically create instances of the type, bind the type to an existing object, or obtain the type from an existing object.
2. The application needs to load a specific type from a specific program set at runtime, so that reflection can be used for a task.
3. Reflection main applications and class libraries. These class libraries need to know a type definition to provide more functions. Application highlights:
1. In real applications, few applications need to use the reflection type.
2. dynamic reflection binding sacrifices performance.
3. Some metadata information cannot be obtained through reflection.
4. Some reflection types are specially used for the development and use of CLR development compilers, so you must realize that not all reflection types are suitable for everyone. Application instance:
In actual development, we often need to read data from the database and assign values to the corresponding attributes of the object class. For example:
General Practice
Public role [] getroles (INT blogid)
{
System. Collections. arraylist Al = new system. Collections. arraylist ();
Idatareader reader = dbprovider. instance (). getroles (blogid );
Try
{
While (reader. Read ())
{
Role role = new role ();
If (Reader ["roleid"]! = Dbnull. value)
{
Role. roleid = (INT) Reader ["roleid"];
}
If (Reader ["name"]! = Dbnull. value)
{
Role. Name = (string) Reader ["name"];
}
If (Reader ["Description"]! = Dbnull. value)
{
Role. Description = (string) Reader ["Description"];
}
// Readertoobject (reader, role );
Al. Add (role );
}
}
Finally
{
Reader. Close ();
}
Return (role []) Al. toarray (typeof (role ));
} Code private void readertoobject (idatareader reader, object targetobj) implemented through the reflection mechanism)
{
For (INT I = 0; I <reader. fieldcount; I ++)
{
System. reflection. propertyinfo =
Targetobj. GetType (). getproperty (reader. getname (I ));
If (propertyinfo! = NULL)
{
If (reader. getvalue (I )! = Dbnull. value)
{
If (propertyinfo. propertytype. isenum)
{
Propertyinfo. setvalue (targetobj,
Enum. toobject (propertyinfo. propertytype,
Reader. getvalue (I), null );
}
Else
{
Propertyinfo. setvalue (targetobj, reader. getvalue (I), null );
}
}
}
}
Analysis of the above transformation code
1. The general practice is to check whether the reader value is dbnull every time a value is assigned to the role attribute, and a lot of repeated code appears;
2. Generally, each time a role attribute is assigned a value, type conversion is required. The type of the role attribute is known and such conversion can be automatically completed through reflection;
3. Generally, each time a role attribute is assigned a value, the role attribute must correspond to the database field. If we ensure that the same name is used for the database field and the object class attribute when designing the database and object class, we can use reflection to automatically map the attributes and fields through code. Even if the database field and attribute are different, we can change the query statement to achieve this.
Reflection of the appdomain Assembly: When you need to reflect all the Assembly contained in the appdomain, the example is as follows:
Static void main
{
// Call all the assembly of appdomain through getassemblies
Foreach (Assembly assem in appdomain. currentdomain. getassemblies ())
{
// Reflect the information of the current Assembly
Reflector. reflectonassembly (assem)
}
} Note: calling the getassemblies method of the appdomain object will return an array consisting of system. reflection. Assembly elements. Reflection of a single assembly: The method described above is to reflect all the assembly of the appdomain. We can display the calling of one of the Assembly. The system. reflecton. assembly type provides the following three methods:
1. Load Method: A strongly recommended method. The load method carries an Assembly flag and loads it. Load will cause the CLR to apply the policy to the Assembly, successively in the global assembly buffer, find the Assembly under the application base directory and private path. If the Assembly cannot be found, the system throws an exception.
2. loadfrom method: Pass the path name (including the extension) of an assembly file. CLR loads the specified assembly. The passed parameter cannot contain any information about the version number, culture, and public key information. If the Assembly cannot be found in the specified path, an exception is thrown.
3. loadwithpartialname: never use this method, because the application cannot determine the version of the loaded assembly. The only purpose of this method is to help customers who use a certain behavior provided by the. NET Framework in the testing stage of the. NET Framework. This method will eventually be discarded. Note: system. appdomain also provides a load method, which is different from the static load method of assembly. The load method of appdomain is an instance method, and a reference to the Assembly is returned, the static load of Assembly sends the Assembly value encapsulation back to the appdomain that sends the call. try to avoid using the load method of appdomain to obtain the type information using reflection: After finishing the previous lecture on Assembly reflection, let's talk about the third layer in the reflection hierarchy model, type reflection.
A simple example of using reflection to obtain type information: using system;
Using sytem. reflection;
Class reflecting
{
Static void main (string [] ARGs)
{
Reflecting reflect = new reflecting (); // defines a new class.
// Call a reflecting.exe Assembly myassembly Assembly assembly.loadfrom(“reflecting.exe ")
Reflect. getreflectioninfo (myassembly); // gets the reflection Information
} // Define a method to obtain the reflected content
Void getreflectioninfo (Assembly myassembly)
{
Type [] typearr = myassemby. gettypes (); // obtain the type
Foreach (type in typearr) // obtain detailed information for each type
{
// Obtain the structure information of the type
Constructorinfo [] myconstructors = type. getconstructors; // obtain the field information of the type.
Fieldinfo [] myfields = type. getfiedls () // obtain method information
Methodinfo mymethodinfo = type. getmethods (); // get the Property Information
Propertyinfo [] myproperties = type. getproperties // obtain event information
Eventinfo [] myevents = type. getevents;
}
}
}
Other methods for getting type objects:
1. The system. Type parameter is of the string type. The full name of the type (including its namespace) must be specified for this string)
2. system. Type provides two instance methods: getnestedtype and getnestedtypes.
3. The instance methods provided by syetem. reflection. Assembly are GetType, gettypes, and getexporedtypes.
4. system. reflection. Moudle provides the following instance methods: GetType, gettypes, and findtypes:
The member of the reflection type is the bottom layer of data in the reflection hierarchy model. We can use the getmembers method of the type object to obtain a type member. If we use getmembers without parameters, it only returns static variables and instance members of the public definition of this type, you can also use getmembers with parameters to return the specified type members through parameter settings. For more information about the parameters, see system. reflection. bindingflags Enumeration type in msdn. For example:
// Set the member content of the type to be returned
Bindingflags BF = bingdingflags. declaredonly | bingdingflags. nonpublic | bingdingflags. Public;
Foreach (memberinfo mi int T. getmembers (BF ))
{
Writeline (MI. membertype) // output the specified type member
} Create an instance of the type through reflection: You can obtain the assembly type through reflection, so that we can create a new instance of the type based on the obtained assembly type, this is also the function of creating objects at runtime to realize late binding.
We can achieve this through the following methods:
1. createinstance method of system. activator. This method returns the reference of the new object. For more information, see msdn.
2. The createinstancefrom of system. activator is similar to the previous method, but the type and its assembly must be specified.
3. Method of system. appdomain: createinstance, createinstanceandunwrap, createappsancefrom, and createappsacefromanunwrap
4. invokemember instance method of system. Type: This method returns a constructor that matches the input parameter and constructs this type.
5. system. reflection. constructinfo invoke instance method reflection interface: If you want to obtain a set of all interfaces inherited by the type, you can call findinterfaces getinterface or getinterfaces of the type. All these methods can only return directly inherited interfaces of this type. They do not return interfaces inherited from an interface. To return the basic interface, you must call the preceding method again. Reflection performance: When reflection is used to call a type or trigger method, or when a field or attribute is accessed, CLR needs to do more work: Check parameters, check permissions, and so on, therefore, the speed is very slow. Therefore, do not use reflection for programming. You can use the following methods to write a dynamic Constructor (late binding:
1. inherit from the class. Let this type be derived from a known basic type during compilation, generate an instance of this type at runtime, and place its reference to a variable of its basic type, then, call the virtual method of the basic type.
2. Implemented through interfaces. At runtime, construct an instance of this type, place its reference to a variable of its interface type, and then call the virtual method defined by this interface.
3. Implemented through delegation. Let this type implement a method. Its name and prototype are consistent with a delegate that is known during compilation. Construct an instance of this type at runtime, then construct the instance of the delegate using the object and name of the method, and then call the method you want through the delegate. This method is more efficient than the previous two methods.