Http://hi.baidu.com/linrao/blog/item/6086dc3918df18d5d4622534.html
What is dynamic assembly
A dynamic assembly is an assembly that is not compiled to the main program, but dynamically called or generated by the main program at runtime. Dynamic link library (DLL) is a collection of classes and methods that can be loaded and shared by different execution programs. The Assembly generated by C # is also a DLL. In practical applications, some programs do not have to load all DLL files to the memory at startup, but dynamically load or create as needed. C # reflection and late binding provide great help for this operation. This article describes how to create a specific class object from a dynamic assembly, as well as the serialization and deserialization of the object.
C # Assembly Loading Mechanism
We know that a C # application will automatically search for all the assemblies in the same directory as the application in the current application domain (appdomain, check whether the Assembly exists. If not, an exception is thrown. Therefore, if our dynamic assembly is put in the same directory as the application, serialization and deserialization will not occur, however, once we place the assembly of various functions in different inner folders, additional operations are required for deserialization. A simple example is provided to describe the serialization and deserialization of a dynamic assembly.
Dynamic assembly loading example
First, create a new main project (console application) and name it testapp. This program is used to load dynamic assembly. Define an interface ipersoncontrol in the main program to enable the dynamic assembly to implement this interface, so that you can conveniently call the methods of the dynamic assembly. The interface is very simple. The print () function is used to print the output.
using System;namespace TestApp{ public interface IPersonControl { void Print(); }}
OK. Create an assembly, create a class library project, name it dynamicassembly, and add a reference to testapp. Then we will write a simple person class that contains only two variables and attributes: name and age. At the same time, we will implement the ipersoncontrol interface to output the name and age. The class is defined as follows:
using System;using TestApp;namespace DynamicAssembly{ [Serializable] public class Person : IPersonControl { private string name; public string Name { get { return name; } set { name = value; } } private int age; public int Age { get { return age; } set { age = value; } } public Person(string name, int age) { this.name = name; this.age = age; } public void Print() { Console.WriteLine("name:{0} age:{1}", name, age); } }}
Well, this simple assembly is ready. Build it and then you can see dynamicassembly in the bin/DEBUG directory. DLL compiled file, copy it to the bin/DEBUG directory where the main program project (testapp) is located, so that testapp can be called dynamically.
At this time, we focus on testapp, dynamically load dynamicassembly. dll in the main function, create an instance of the person class, and call its print method. First, reference the class library that handles reflection.
using System.Reflection;
Then add and modify the main function as follows:
Static void main (string [] ARGs) {// dynamically load the Assembly dynamicassembly. DLL Assembly myassembly = assembly. loadfrom ("dynamicassembly. DLL "); // obtain all classes in the assembly type [] types = myassembly. gettypes (); // find the person class type mytype = NULL in the Assembly; foreach (type in types) {If (type. name = "person") {mytype = type ;}// create this dynamic class instance object o = activator. createinstance (mytype, new object [] {"shinichi_wtn", 22}); // print method in the execution class ipersoncontrol iperson = O as ipersoncontrol; iperson. print (); console. read ();}
Run the program and the output is
name:shinichi_wtn age:22
Therefore, it is easy to dynamically load the Assembly and create new objects.
Serialization of dynamic assembly
Sometimes, we want to save this object, namely the serialization operation. We add two functions to process the serialization and deserialization Operations respectively (using system. runtime. serialization. formatters. binary), as follows:
static void SerializeObject(object o, string path){ BinaryFormatter binFormatter = new BinaryFormatter(); using (FileStream fs = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.None)) { binFormatter.Serialize(fs, o); }}static object DeserializeObject(string path){ BinaryFormatter binFormatter = new BinaryFormatter(); object o; using (FileStream fs = new FileStream(path, FileMode.Open)) { o = binFormatter.Deserialize(fs); } return o;}
Add the serialization operation to the main function.
... // Create the dynamic class instance object o = activator. createinstance (mytype, new object [] {"shinichi_wtn", 22}); // print method in the execution class ipersoncontrol iperson = O as ipersoncontrol; iperson. print (); // deserialize the object to the local serializeobject (O, "person. dat ");...
Run the following command to obtain the object serialization file person. dat in the bin/DEBUG directory.
Deserialization of dynamic assembly
Then, we will test the restoration from person. dat to the person object. Modify the main function as follows:
Static void main (string [] ARGs) {// restore the serialized object o = deserializeobject ("person. dat "); // print method in the execution class ipersoncontrol iperson = O as ipersoncontrol; iperson. print (); console. read ();}
Run the program and the output is
name:shinichi_wtn age:22
At this time, it is curious, because the dynamicassembly is not added to the program. DL references are not dynamically loaded, but the fact is that they can be deserialized directly. We can see that when an unknown assembly is encountered during program execution, the main program will automatically find the assembly in the same directory. If the unknown Assembly exists, it will be automatically loaded. You can use a simple method to test this conjecture.
Static void main (string [] ARGs) {console. writeline ("--- Before deserialization ---"); foreach (Assembly in appdomain. currentdomain. getassemblies () {console. writeline (assembly. fullname);} console. writeline ("--- after deserialization ---"); // restores the serialized object o = deserializeobject ("person. dat "); foreach (Assembly in appdomain. currentdomain. getassemblies () {console. writeline (assembly. fullname);} console. read ();}
After running, it is found that dynamicassembly. dll is not output before deserialization. After deserialization, dynamicassembly. dll is automatically loaded when the program is running. This raises a problem. When dynamicassembly. dll is not in the main program directory, an exception is thrown. We put dynamicassembly. dll in the lib directory, and then run the program, directly exception ......
When developing large software, there may be many modules and class libraries, and it is impossible to put all DLL files in a directory with the main program, therefore, you must handle how to operate a dynamic assembly that cannot be automatically loaded by a program. This can be done through the assemblyresolve event in appdomain. This event is triggered when the corresponding assembly cannot be found in the application domain. If we specify the Assembly location in the event, then it can be called by the application domain. OK, the Code is as follows (using system. componentmodel ;)
Static void main (string [] ARGs) {// Add the handler appdomain that cannot find the assembly. currentdomain. assemblyresolve + = new resolveeventhandler (currentdomain_assemblyresolve); // deserialize the object to a local object o = deserializeobject ("person. dat "); // print method in the execution class ipersoncontrol iperson = O as ipersoncontrol; iperson. print (); console. read ();} static Assembly currentdomain_assemblyresolve (Object sender, resolveeventargs e) {// manually specify the position of the Assembly and return assembly. loadfrom ("Lib \ dynamicassembly. DLL ");}
Run the program and the output is
name:shinichi_wtn age:22
The problem is solved, that is, by manually specifying the assembly, the error that cannot be found during deserialization can be solved. With this foundation, we become more flexible in serialization and deserialization. This is when developing an open software with plug-in/component/module functions, it is indeed a good thing to create objects for dynamically loaded assemblies and perform serialization and deserialization operations.