Use reflection to dynamically create objects (from zhangyi's blog)
I sent an article two days ago.ArticleA strange problem that occurs when objects are dynamically instantiated through reflection, which puzzles some problems in reflection. Over the past few days, I have been viewing msdn and surfing the internet to solve this problem.
In vs. net, there are many methods to dynamically call object constructors. First, use the createinstance () method of the activator class. This method is also used in remoting. It actually creates an object type locally or remotely, or gets a reference to an existing remote object. Its method signature is: public static object createinstance (type); (there are other overload methods). Note that its return value is object. The return value of msdn is described as follows: references the newly created object.
The second is to use the createinstance () method of the Assembly class (). The method name is the same as the previous one, but it is not a static method. Assembly is in the system. Reflection namespace. Method Signature: Public object createinstance (type); (there are also other overload methods) the returned value is still object, and msdn describes the returned value as an instance of this type of object, its regions, parameters, and associated editingProgramAnd the activation attribute is set to null reference (nothing in Visual Basic), bindingflags is set to public or instance, or null reference (nothing) (if typename is not found ).
Of course, there are other methods. For example, after obtaining method information through methodinfo, determine whether to construct a function based on the isconstructor attribute, obtain parameters based on the getparamters () method, and finally call the method through the invoke () method, and so on ....... You can refer to msdn.
Here, I want to simplify the problem and only call its default constructor. Use the createinstance () method to obtain the object and then convert it to the actual custom object type. It turns out that this conversion is abnormal. I still don't know the root cause. The preliminary guess is that for dynamically loaded assemblies and manually added assemblies, the Framework regards the two as different assemblies, even if we use the same DLL.
I also noticed that actovator. createinstance () returns a reference to the newly created object. Is it just a reference? However, the Assembly. createinstance () method returns an object instance according to the description of msdn, but the same exception is still thrown. Therefore, I cannot explain the specific cause of the problem.
Indeed vs. NET is profound and profound, and many internal operating mechanisms are unknown. Well, we know it, but we don't know why. At least I already know how to use reflection to dynamically create objects! As long as it is used, you can leave and seek the second.
Using Reflection to dynamically create objects is actually using assembly to dynamically load DLL. The so-called "object" can be divided into two types. The solution varies with different types.
1. class objects provided by. net, such as form objects and control objects.
This is also frequently used in program development. Generally, we develop applications to define the interface. How many windows are there, how many controls are there, and put them in the project in advance. However, when designing interactions, you also need to consider user requests. You may want some forms to determine the loading time. That is to say, it is necessary to provide the runtime loading function. In this case, you need to dynamically create an object through reflection. (The loaded form object DLL is usually placed in the configuration file. In. net, there is a special configuration file, which is in XML format. I want to write a special article about the configuration file. In this article, my example is fixed assembly loading .)
1. Create a form object to be dynamically loaded
First, create a form object firstform, which has only one control lable to display the name of the form. Then we compile it into the DLL file firstform. dll and put it in E: \ autoform. (To generate a DLL file instead of EXE, right-click the firstforms project in Solution Explorer and select Properties ). Select class library in the output type combo box ).)
The Assembly name of this object is firstform. dll and the type is firstform. form1.
2. Create an application and dynamically load the object
Start a new windows form project. Name it autoloadform. In the blank form form1 contained in the new projectIsmdicontainerProperty changedTrue. In this way, the form becomes an MDI parent form. Change the size of the form so that the length and width of the form are approximately twice the default size.
Drag a panel control to the form and set itsDockProperty to connect it to the top of the form. Change the Panel size so that it is about 50px in height.
Drag a combo box to the Panel. Name it cboforms, and thenDropdownstyleSetDropdownlist.
Finally, drag a button to the Panel. Name it btnloadform, and thenTextSet propertyLoad Form.
In this case, form1 should be 1.
Then add a namespace for the program:
Using system. reflecton;
Click the btnloadform control and write the followingCode:
Private Void Btnloadform_click ( Object Sender, system. eventargs E)
{
Assembly = Assembly. loadfrom ( @" E: \ autoformfirstform. dll " );
Type type = Assembly. GetType ( " Firstform. form1 " );
Object OBJ = Activator. createinstance (type );
Form formtoshow = (Form) OBJ;
Formtoshow. mdiparent = This ;
Formtoshow. Show ();
}
Code Description:
1) First, load the DLL file through Assembly. loadfrom;
2) use GetType () to obtain the type of the Form class object to be created. Note: In the GetType () method, the parameter is of the type name, which is of the string type, and the name must be of the type fullname, that is, namespace name. Class Name;
3) create an object of this type using the activator. createinstance () method and return the object.
4) Forcibly convert the object to form type.
5) The call is complete.
Run the program and click the button. The result is as follows:
Conclusion: we can see that for the Class Object provided by. Net itself, we can directly forcibly convert it. No problems.
Ii. Custom object
As mentioned earlier, forced conversion of custom objects throws an exception. Therefore, we need to make some changes.
We said that the Dynamically Loaded DLL and manually added DLL references will not be considered as the same assembly. So what should we do? Think about it. By the way, you should use interfaces. However, the method for using interfaces here is a little special. Follow the steps to explain.
1. Create an interface that includes methods and attributes for loading object classes:
Create a new "class library" project named autoobjectinterface:
Using System;
Namespace Autoobjectinterface
{
Public Interface Iautoobject
{
VoidPrint (StringS );
}
}
This interface is very simple. It only provides a print () method.
Compile it into a DLL file named autoobjectinterface.
2. Create a custom Class Object:
Create a new "class library" project named autoobject and add the aforementioned interface DLL reference:
Using System;
Namespace Autoobject
{
Public Class Testobject: autoobjectinterface. iautoobject
{
Public Testobject ()
{
}
Public Void Print ( String S)
{
Console. writeline (s );
}
}
}
This class implements the interface created in step 1. Note that the interface implemented here is not directly written in this class, but an independent DLL. In this class, it is the DLL with this interface added, and then implement it. This is a special aspect of the interface used previously. The reason for this is that this interface dll must also be referenced during dynamic loading. The dynamically created object is converted to this interface object. Because the actual class and the dynamically created class both reference and implement the interface DLL, the conversion can be successful. This is the key to implementation!
Some people may wonder: can we place the interface in the class to be created and implement it. Compile the DLL file, load the DLL dynamically, and manually add the DLL. The dynamically created object is forcibly converted to this interface type. Isn't it possible? The answer is no. Why? Don't ask me. I don't know either! In short, the method I am talking about now is the best way to dynamically create custom objects through reflection !!
Someone may say that I am too random! If you don't believe it, try it. If another method is successful, I must correct the error. At least now I can be so arbitrary.
Let's get down to the truth. Now we will compile the class into DLL. Named autoobject. dll and put it in E: \ newobject.
3. Use reflection to dynamically create the object:
Create a console project named studyreflection and add the DLL reference of the previously created interface. The Code is as follows:
Using System;
Using System. reflection;
Namespace Studyreflection
{
Class Class1
{
// The main entry point of the application.
[Stathread]
Static Void Main ( String [] ARGs)
{
Assembly = Assembly. loadfrom ( @" E: newobjectautoobject. dll " );
Type type = Assembly. GetType ( " Autoobject. testobject " );
Object OBJ = Activator. createinstance (type );
Autoobjectinterface. iautoobject iobj = (Autoobjectinterface. iautoobject) OBJ;
Iobj. Print ( " Wayfarer " );
Console. Readline ();
}
}
}
Note: This code is similar to the object provided by. Net itself. The key difference is forced conversion. Because it is a custom object, we do not know why the conversion is performed, so we need to add an interface reference. Convert to the interface type during conversion: autoobjectinterface. iautoobject iobj=(Autoobjectinterface. iautoobject) OBJ;
In this way, we can call the print () method of class objects through the interface object instance. After running, everything is OK.
Conclusion: When Using Reflection to dynamically create an object, be sure to differentiate the type of the created object. For a custom object, you must use a separate interface to convert the type.