C#動態創建和動態使用程序集、類、方法、字段等


    

C#動態創建和動態使用程序集、類、方法、字段等

 
  首先需要知道動態創建這些類型是使用的一些什麼技術呢?其實只要相關動態加載程序集呀,類呀,都是使用反射,那麼動態創建也一樣使用的是反射,是屬於反射的技術!也就是將對象或者數據映射成一個對象或者程序集保存起來而已。

  首先我們需要了解每個動態類型在.net中都是用什麼類型來表示的。

程序集:System.Reflection.Emit.AssemblyBuilder(定義並表示動態程序集)

構造函數:System.Reflection.Emit.ConstructorBuilder(定義並表示動態類的構造函數)

自定義屬性:System.Reflection.Emit.CustomAttributeBuilder(幫助生成自定義屬性 使用構造函數傳遞的參數來生成類的屬性)

枚舉:System.Reflection.Emit.EnumBuilder(說明並表示枚舉類型)

事件:System.Reflection.Emit.EventBuilder(定義類的事件)

字段:System.Reflection.Emit.FieldBuilder(定義並表示字段。無法繼承此類)

局部變量:System.Reflection.Emit.LocalBuilder(表示方法或構造函數內的局部變量)

方法:System.Reflection.Emit.MethodBuilder(定義並表示動態類的方法(或構造函數))

模塊:System.Reflection.Emit.ModuleBuilder(定義和表示動態程序集中的模塊)

參數:System.Reflection.Emit.ParameterBuilder(創建或關聯參數信息 如:方法參數,事件參數等)

屬性:System.Reflection.Emit.PropertyBuilder(定義類型的屬性 (Property))

類:System.Reflection.Emit.TypeBuilder(在運行時定義並創建類的新實例)

  我們有了這些類型,基本上就可以動態創建我們的任何需要使用的類型,當然很多可以動態創建的類型我不可能都介紹完,如果在項目中有需要可以去查閱MSDN,裏面都有DEMO的,主要的問題就是要理解每一種類型的定義,比如:程序集加載是靠AppDomain,程序集裏包含多個模塊,模塊裏可以聲明類,類裏可以創建方法、屬性、字段。方法需要在類中纔可以創建的,局部變量是聲明在方法體內等等規則。看MSDN就非常容易弄懂了。

1.如何動態創建它們了

AppDomain:應用程序域(由 AppDomain 對象表示)爲執行託管代碼提供隔離、卸載和安全邊界。AppDomain同時可以載入多個程序集,共同來實現功能。

程序集:簡單來說就是一個以公共語言運行庫(CLR)爲宿主的、版本化的、自描述的二進制文件。(說明:定義來自C#與.NET3.5高級程序設計(第四版))

模塊:類似於以前的單元,用於分割不同的類和類型,以及資源(resource, 資源記錄就是字符串,圖象以及其它數據,他們只在需要的時候纔會被調入內存)。類型的Meta信息也是模塊的一部分。多個模塊組建成一個程序集。

所謂動態就是在程序運行時,動態的創建和使用。

直接看代碼吧,其實超級簡單。

  

  1. //動態創建程序集  
  2.             AssemblyName DemoName = new AssemblyName("DynamicAssembly");  
  3.             AssemblyBuilder dynamicAssembly = AppDomain.CurrentDomain.DefineDynamicAssembly(DemoName, AssemblyBuilderAccess.RunAndSave);  
  4.             //動態創建模塊  
  5.             ModuleBuilder mb = dynamicAssembly.DefineDynamicModule(DemoName.Name, DemoName.Name + ".dll");  
  6.             //動態創建類MyClass  
  7.             TypeBuilder tb = mb.DefineType("MyClass", TypeAttributes.Public);  
  8.             //動態創建字段  
  9.             FieldBuilder fb = tb.DefineField(""typeof(System.String), FieldAttributes.Private);    
  10.             //動態創建構造函數  
  11.             Type[] clorType = new Type[] { typeof(System.String) };  
  12.             ConstructorBuilder cb1 = tb.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard, clorType);  
  13.             //生成指令  
  14.             ILGenerator ilg = cb1.GetILGenerator();//生成 Microsoft 中間語言 (MSIL) 指令  
  15.             ilg.Emit(OpCodes.Ldarg_0);  
  16.             ilg.Emit(OpCodes.Call, typeof(object).GetConstructor(Type.EmptyTypes));  
  17.             ilg.Emit(OpCodes.Ldarg_0);  
  18.             ilg.Emit(OpCodes.Ldarg_1);  
  19.             ilg.Emit(OpCodes.Stfld, fb);  
  20.             ilg.Emit(OpCodes.Ret);  
  21.             //動態創建屬性  
  22.             PropertyBuilder pb = tb.DefineProperty("MyProperty", PropertyAttributes.HasDefault, typeof(string), null);  
  23.             //動態創建方法  
  24.             MethodAttributes getSetAttr = MethodAttributes.Public | MethodAttributes.SpecialName;  
  25.             MethodBuilder myMethod = tb.DefineMethod("get_Property", getSetAttr, typeof(string), Type.EmptyTypes);  
  26.             //生成指令  
  27.             ILGenerator numberGetIL = myMethod.GetILGenerator();  
  28.             numberGetIL.Emit(OpCodes.Ldarg_0);  
  29.             numberGetIL.Emit(OpCodes.Ldfld, fb);  
  30.             numberGetIL.Emit(OpCodes.Ret);  
  31.             //保存動態創建的程序集  
  32.             dynamicAssembly.Save(DemoName.Name + ".dll");  
<span style="font-size:14px;">//動態創建程序集
            AssemblyName DemoName = new AssemblyName("DynamicAssembly");
            AssemblyBuilder dynamicAssembly = AppDomain.CurrentDomain.DefineDynamicAssembly(DemoName, AssemblyBuilderAccess.RunAndSave);
            //動態創建模塊
            ModuleBuilder mb = dynamicAssembly.DefineDynamicModule(DemoName.Name, DemoName.Name + ".dll");
            //動態創建類MyClass
            TypeBuilder tb = mb.DefineType("MyClass", TypeAttributes.Public);
            //動態創建字段
            FieldBuilder fb = tb.DefineField("", typeof(System.String), FieldAttributes.Private);  
            //動態創建構造函數
            Type[] clorType = new Type[] { typeof(System.String) };
            ConstructorBuilder cb1 = tb.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard, clorType);
            //生成指令
            ILGenerator ilg = cb1.GetILGenerator();//生成 Microsoft 中間語言 (MSIL) 指令
            ilg.Emit(OpCodes.Ldarg_0);
            ilg.Emit(OpCodes.Call, typeof(object).GetConstructor(Type.EmptyTypes));
            ilg.Emit(OpCodes.Ldarg_0);
            ilg.Emit(OpCodes.Ldarg_1);
            ilg.Emit(OpCodes.Stfld, fb);
            ilg.Emit(OpCodes.Ret);
            //動態創建屬性
            PropertyBuilder pb = tb.DefineProperty("MyProperty", PropertyAttributes.HasDefault, typeof(string), null);
            //動態創建方法
            MethodAttributes getSetAttr = MethodAttributes.Public | MethodAttributes.SpecialName;
            MethodBuilder myMethod = tb.DefineMethod("get_Property", getSetAttr, typeof(string), Type.EmptyTypes);
            //生成指令
            ILGenerator numberGetIL = myMethod.GetILGenerator();
            numberGetIL.Emit(OpCodes.Ldarg_0);
            numberGetIL.Emit(OpCodes.Ldfld, fb);
            numberGetIL.Emit(OpCodes.Ret);
            //保存動態創建的程序集
            dynamicAssembly.Save(DemoName.Name + ".dll");</span>

現在開始動態創建類:

構造函數:System.Reflection.ConstructorInfo(發現類構造函數的屬性並提供對構造函數元數據的訪問權)

事件:System.Reflection.EventInfo(發現事件的屬性並提供對事件元數據的訪問權)

字段:System.Reflection.FieldInfo(發現字段屬性並提供對字段元數據的訪問權)

方法:System.Reflection.MemberInfo(獲取有關成員屬性的信息並提供對成員元數據的訪問)

成員:System.Reflection.MemberInfo(獲取有關成員屬性的信息並提供對成員元數據的訪問)

參數:System.Reflection.ParameterInfo(發現參數屬性並提供對參數元數據的訪問)

屬性:System.Reflection.PropertyInfo (發現屬性 (Property) 的屬性 (Attribute) 並提供對屬性 (Property) 元數據的訪問)

同樣這是一種延伸閱讀,只是先對這些進行了解,如果不知道的話,可能對動態的使用類型就無法下手了。

今天我做了一個Demo,先上Demo吧,然後在來解釋程序是如何執行的。

  1. /動態創建的動態類型  
  2. public static Type DynamicCreateType()  
  3.         {  
  4.             //動態創建程序集  
  5.             AssemblyName DemoName = new AssemblyName("DynamicAssembly");  
  6.             AssemblyBuilder dynamicAssembly = AppDomain.CurrentDomain.DefineDynamicAssembly(DemoName, AssemblyBuilderAccess.RunAndSave);  
  7.             //動態創建模塊  
  8.             ModuleBuilder mb = dynamicAssembly.DefineDynamicModule(DemoName.Name, DemoName.Name + ".dll");  
  9.             //動態創建類MyClass  
  10.             TypeBuilder tb = mb.DefineType("MyClass", TypeAttributes.Public);  
  11.             //動態創建字段  
  12.             FieldBuilder fb = tb.DefineField("myField"typeof(System.String), FieldAttributes.Private);    
  13.             //動態創建構造函數  
  14.             Type[] clorType = new Type[] { typeof(System.String) };  
  15.             ConstructorBuilder cb1 = tb.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard, clorType);  
  16.             //生成指令  
  17.             ILGenerator ilg = cb1.GetILGenerator();//生成 Microsoft 中間語言 (MSIL) 指令  
  18.             ilg.Emit(OpCodes.Ldarg_0);  
  19.             ilg.Emit(OpCodes.Call, typeof(object).GetConstructor(Type.EmptyTypes));  
  20.             ilg.Emit(OpCodes.Ldarg_0);  
  21.             ilg.Emit(OpCodes.Ldarg_1);  
  22.             ilg.Emit(OpCodes.Stfld, fb);  
  23.             ilg.Emit(OpCodes.Ret);  
  24.             //動態創建屬性  
  25.             PropertyBuilder pb = tb.DefineProperty("MyProperty", PropertyAttributes.HasDefault, typeof(string), null);  
  26.             //動態創建方法  
  27.             MethodAttributes getSetAttr = MethodAttributes.Public | MethodAttributes.SpecialName;  
  28.             MethodBuilder myMethod = tb.DefineMethod("get_Field", getSetAttr, typeof(string), Type.EmptyTypes);  
  29.             //生成指令  
  30.             ILGenerator numberGetIL = myMethod.GetILGenerator();  
  31.             numberGetIL.Emit(OpCodes.Ldarg_0);  
  32.             numberGetIL.Emit(OpCodes.Ldfld, fb);  
  33.             numberGetIL.Emit(OpCodes.Ret);  
  34.             //使用動態類創建類型  
  35.             Type classType = tb.CreateType();  
  36.             //保存動態創建的程序集 (程序集將保存在程序目錄下調試時就在Debug下)  
  37.             dynamicAssembly.Save(DemoName.Name + ".dll");  
  38.             //創建類  
  39.             return classType;  
  40.         }  
<span style="font-size:14px;">/動態創建的動態類型
public static Type DynamicCreateType()
        {
            //動態創建程序集
            AssemblyName DemoName = new AssemblyName("DynamicAssembly");
            AssemblyBuilder dynamicAssembly = AppDomain.CurrentDomain.DefineDynamicAssembly(DemoName, AssemblyBuilderAccess.RunAndSave);
            //動態創建模塊
            ModuleBuilder mb = dynamicAssembly.DefineDynamicModule(DemoName.Name, DemoName.Name + ".dll");
            //動態創建類MyClass
            TypeBuilder tb = mb.DefineType("MyClass", TypeAttributes.Public);
            //動態創建字段
            FieldBuilder fb = tb.DefineField("myField", typeof(System.String), FieldAttributes.Private);  
            //動態創建構造函數
            Type[] clorType = new Type[] { typeof(System.String) };
            ConstructorBuilder cb1 = tb.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard, clorType);
            //生成指令
            ILGenerator ilg = cb1.GetILGenerator();//生成 Microsoft 中間語言 (MSIL) 指令
            ilg.Emit(OpCodes.Ldarg_0);
            ilg.Emit(OpCodes.Call, typeof(object).GetConstructor(Type.EmptyTypes));
            ilg.Emit(OpCodes.Ldarg_0);
            ilg.Emit(OpCodes.Ldarg_1);
            ilg.Emit(OpCodes.Stfld, fb);
            ilg.Emit(OpCodes.Ret);
            //動態創建屬性
            PropertyBuilder pb = tb.DefineProperty("MyProperty", PropertyAttributes.HasDefault, typeof(string), null);
            //動態創建方法
            MethodAttributes getSetAttr = MethodAttributes.Public | MethodAttributes.SpecialName;
            MethodBuilder myMethod = tb.DefineMethod("get_Field", getSetAttr, typeof(string), Type.EmptyTypes);
            //生成指令
            ILGenerator numberGetIL = myMethod.GetILGenerator();
            numberGetIL.Emit(OpCodes.Ldarg_0);
            numberGetIL.Emit(OpCodes.Ldfld, fb);
            numberGetIL.Emit(OpCodes.Ret);
            //使用動態類創建類型
            Type classType = tb.CreateType();
            //保存動態創建的程序集 (程序集將保存在程序目錄下調試時就在Debug下)
            dynamicAssembly.Save(DemoName.Name + ".dll");
            //創建類
            return classType;
        }</span>



 

執行的主要方法


  1. static void Main(string[] args)  
  2. {  
  3.     //動態創建的類類型  
  4.     Type classType = DynamicCreateType();  
  5.     //調用有參數的構造函數  
  6.     Type[] ciParamsTypes = new Type[] { typeof(string) };  
  7.     object[] ciParamsValues = new object[] { "Hello World" };  
  8.     ConstructorInfo ci = classType.GetConstructor(ciParamsTypes);  
  9.     object Vector = ci.Invoke(ciParamsValues);  
  10.     //調用方法  
  11.     object[] methedParams=new object[]{};  
  12.     Console.WriteLine(classType.InvokeMember("get_Field", BindingFlags.InvokeMethod, null, Vector, methedParams));  
  13.     Console.ReadKey();  
  14. }   
<span style="font-size:14px;">static void Main(string[] args)
{
    //動態創建的類類型
    Type classType = DynamicCreateType();
    //調用有參數的構造函數
    Type[] ciParamsTypes = new Type[] { typeof(string) };
    object[] ciParamsValues = new object[] { "Hello World" };
    ConstructorInfo ci = classType.GetConstructor(ciParamsTypes);
    object Vector = ci.Invoke(ciParamsValues);
    //調用方法
    object[] methedParams=new object[]{};
    Console.WriteLine(classType.InvokeMember("get_Field", BindingFlags.InvokeMethod, null, Vector, methedParams));
    Console.ReadKey();
} </span>


我創建了一個類,類裏創建了有一個字段、有一個參數的構造函數、一個屬性、有一個參數的構造函數和一個方法。用有參數的構造函數來初始化字段myField,然後調用get_Field方法返回myField字段的值。控制檯程序顯示“Hello World!!!”



本文實例講述了C#在運行時動態創建類型的實現方法。是C#項目開發中很實用的技巧。分享給大家供大家參考。具體分析如下:


具體來說,C# 在運行時動態的創建類型是通過動態生成C#源代碼,然後通過編譯器編譯成程序集的方式實現動態創建類型的


主要功能代碼如下:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
public static Assembly NewAssembly()
{
  //創建編譯器實例。  
  provider = new CSharpCodeProvider();
  //設置編譯參數。  
  cp = new CompilerParameters();
  cp.GenerateExecutable = false;
  cp.GenerateInMemory = true;
  
  // Generate an executable instead of 
  // a class library.
  //cp.GenerateExecutable = true;
  
  // Set the assembly file name to generate.
  cp.OutputAssembly = "c:\\1.dll";
  
  // Generate debug information.
  cp.IncludeDebugInformation = true;
  
  
  // Save the assembly as a physical file.
  cp.GenerateInMemory = false;
  
  // Set the level at which the compiler 
  // should start displaying warnings.
  cp.WarningLevel = 3;
  
  // Set whether to treat all warnings as errors.
  cp.TreatWarningsAsErrors = false;
  
  // Set compiler argument to optimize output.
  cp.CompilerOptions = "/optimize";
  
  cp.ReferencedAssemblies.Add("System.dll");
  //cp.ReferencedAssemblies.Add("System.Core.dll");
  cp.ReferencedAssemblies.Add("System.Data.dll");
  //cp.ReferencedAssemblies.Add("System.Data.DataSetExtensions.dll");
  cp.ReferencedAssemblies.Add("System.Deployment.dll");
  cp.ReferencedAssemblies.Add("System.Design.dll");
  cp.ReferencedAssemblies.Add("System.Drawing.dll");
  cp.ReferencedAssemblies.Add("System.Windows.Forms.dll");
  
  //創建動態代碼。  
    
  StringBuilder classSource = new StringBuilder();
  classSource.Append("using System;using System.Windows.Forms;\npublic  class  DynamicClass: UserControl \n");
  classSource.Append("{\n");
  classSource.Append("public DynamicClass()\n{\nInitializeComponent();\nConsole.WriteLine(\"hello\");}\n");
  classSource.Append( "private System.ComponentModel.IContainer components = null;\nprotected override void Dispose(bool disposing)\n{\n");
  classSource.Append( "if (disposing && (components != null)){components.Dispose();}base.Dispose(disposing);\n}\n");
  classSource.Append( "private void InitializeComponent(){\nthis.SuspendLayout();this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);");
  classSource.Append( "this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;this.Name = \"DynamicClass\";this.Size = new System.Drawing.Size(112, 74);this.ResumeLayout(false);\n}");
  //創建屬性。  
  /*************************在這裏改成需要的屬性******************************/
  classSource.Append(propertyString("aaa"));
  classSource.Append(propertyString("bbb"));
  classSource.Append(propertyString("ccc"));
  
  classSource.Append("}");
  
  System.Diagnostics.Debug.WriteLine(classSource.ToString());
   
  //編譯代碼。  
  CompilerResults result = provider.CompileAssemblyFromSource(cp, classSource.ToString());
  if (result.Errors.Count > 0)
  {
 for( int i = 0; i < result.Errors.Count; i ++)
   Console.WriteLine(result.Errors[ i]);
 Console.WriteLine("error");
 return null;
  }
    
  //獲取編譯後的程序集。  
  Assembly assembly = result.CompiledAssembly;
  
  return assembly;
}
  
private static string propertyString(string propertyName)
{
  StringBuilder sbProperty = new StringBuilder();
  sbProperty.Append(" private  int  _" + propertyName + "  =  0;\n");
  sbProperty.Append(" public  int  " + "" + propertyName + "\n");
  sbProperty.Append(" {\n");
  sbProperty.Append(" get{  return  _" + propertyName + ";}  \n");
  sbProperty.Append(" set{  _" + propertyName + "  =  value;  }\n");
  sbProperty.Append(" }");
  return sbProperty.ToString();
}


希望本文所述對大家的C#程序設計有所幫助


發佈了18 篇原創文章 · 獲贊 37 · 訪問量 98萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章