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信息也是模塊的一部分。多個模塊組建成一個程序集。
所謂動態就是在程序運行時,動態的創建和使用。
直接看代碼吧,其實超級簡單。
- //動態創建程序集
- 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 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吧,然後在來解釋程序是如何執行的。
- /動態創建的動態類型
- 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 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>
執行的主要方法
- 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 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#程序設計有所幫助