我尝试并未能适应此代码。这是来自C#语言汇编的动态类生成器。我不能使用DynamicObjects,因为RDLC报表不适用于System.Dynamic中的任何类,但不能用于由程序集生成的类。
我想做的是将属性定义从私有变量更改为get and set方法。如果它可以与两个函数一起使用,则不必成为属性。
下面的代码已注释了我需要更改的部分。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Text;
using System.Threading.Tasks;
using System.Dynamic;
namespace PropertyBuilderExample
{
public class MyClassParent : DynamicObject
{
private dynamic _hostElement;
public dynamic ReadProperty(string name)
{
return hostElement[name];
}
public dynamic WriteProperty(string name, dynamic value)
{
return _hostElement[name] = value;
}
}
public class MyClassBuilder
{
AssemblyName asemblyName;
public MyClassBuilder(string ClassName)
{
this.asemblyName = new AssemblyName(ClassName);
}
public object CreateObject(string[] PropertyNames, Type[] Types)
{
if (PropertyNames.Length != Types.Length)
{
Console.WriteLine("The number of property names should match their corresopnding types number");
}
TypeBuilder DynamicClass = this.CreateClass();
this.CreateConstructor(DynamicClass);
for (int ind = 0; ind < PropertyNames.Count(); ind++)
CreateProperty(DynamicClass, PropertyNames[ind], Types[ind]);
Type type = DynamicClass.CreateType();
return Activator.CreateInstance(type);
}
private TypeBuilder CreateClass()
{
AssemblyBuilder assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(this.asemblyName, AssemblyBuilderAccess.Run);
ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule("MainModule");
TypeBuilder typeBuilder = moduleBuilder.DefineType(this.asemblyName.FullName
, TypeAttributes.Public |
TypeAttributes.Class |
TypeAttributes.AutoClass |
TypeAttributes.AnsiClass |
TypeAttributes.BeforeFieldInit |
TypeAttributes.AutoLayout
, typeof(MyClassParent));
return typeBuilder;
}
private void CreateConstructor(TypeBuilder typeBuilder)
{
typeBuilder.DefineDefaultConstructor(MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName);
}
private void CreateProperty(TypeBuilder typeBuilder, string propertyName, Type propertyType)
{
/* HELP HERE !!!!
AT THIS PLACE THIS CODE DEFINES A PRIVATE VARIABLE TO SAVE AND SERVE THE PROPERTY DATA
WHAT I NEED IS TO CHANGE THIS DEFINITION TO THE PARENT METHOD ON MyClassParent ReadProperty AND WriteProperty
*/
FieldBuilder fieldBuilder = typeBuilder.DefineField("_" + propertyName, propertyType, FieldAttributes.Private);
PropertyBuilder propertyBuilder = typeBuilder.DefineProperty(propertyName, PropertyAttributes.HasDefault, propertyType, null);
MethodBuilder getPropMthdBldr = typeBuilder.DefineMethod("get_" + propertyName, MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig, propertyType, Type.EmptyTypes);
ILGenerator getIl = getPropMthdBldr.GetILGenerator();
getIl.Emit(OpCodes.Ldarg_0);
getIl.Emit(OpCodes.Ldfld, fieldBuilder);
getIl.Emit(OpCodes.Ret);
MethodBuilder setPropMthdBldr = typeBuilder.DefineMethod("set_" + propertyName,
MethodAttributes.Public |
MethodAttributes.SpecialName |
MethodAttributes.HideBySig,
null, new[] { propertyType });
ILGenerator setIl = setPropMthdBldr.GetILGenerator();
Label modifyProperty = setIl.DefineLabel();
Label exitSet = setIl.DefineLabel();
setIl.MarkLabel(modifyProperty);
setIl.Emit(OpCodes.Ldarg_0);
setIl.Emit(OpCodes.Ldarg_1);
setIl.Emit(OpCodes.Stfld, fieldBuilder);
setIl.Emit(OpCodes.Nop);
setIl.MarkLabel(exitSet);
setIl.Emit(OpCodes.Ret);
propertyBuilder.SetGetMethod(getPropMthdBldr);
propertyBuilder.SetSetMethod(setPropMthdBldr);
}
}
}
这是如何使用该奇妙的类生成器
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Text;
using System.Threading.Tasks;
using PropertyBuilderExample;
namespace PropertyBuilderExample
{
class Program
{
static void Main(string[] args)
{
MyClassBuilder MCB=new MyClassBuilder("Student");
var myclass = MCB.CreateObject(new string[3] { "ID", "Name", "Address" }, new Type[3] { typeof(int), typeof(string), typeof(string) });
Type TP = myclass.GetType();
foreach (PropertyInfo PI in TP.GetProperties())
{
Console.WriteLine(PI.Name);
}
Console.ReadLine();
}
}
}
答案 0 :(得分:0)
如何像这样将要生成的代码添加到目标类中
public class MyClassParent : DynamicObject
{
private dynamic _hostElement;
public dynamic ReadProperty(string name)
{
return _hostElement[name];
}
public dynamic WriteProperty(string name, dynamic value)
{
return _hostElement[name] = value;
}
// EDIT:
public int ID
{
get { return ReadProperty("ID"); }
set { WriteProperty("ID", value); }
}
}
并在诸如ILSpy之类的工具中显示结果IL,给出
MyClassParent.get_ID:
IL_0000: nop
IL_0001: ldsfld UserQuery+MyClassParent+<>o__4.<>p__0
IL_0006: brfalse.s IL_000A
IL_0008: br.s IL_002E
IL_000A: ldc.i4.0
IL_000B: ldtoken System.Int32
IL_0010: call System.Type.GetTypeFromHandle
IL_0015: ldtoken UserQuery.MyClassParent
IL_001A: call System.Type.GetTypeFromHandle
IL_001F: call Microsoft.CSharp.RuntimeBinder.Binder.Convert
IL_0024: call System.Runtime.CompilerServices.CallSite<System.Func<System.Runtime.CompilerServices.CallSite,System.Object,System.Int32>>.Create
IL_0029: stsfld UserQuery+MyClassParent+<>o__4.<>p__0
IL_002E: ldsfld UserQuery+MyClassParent+<>o__4.<>p__0
IL_0033: ldfld System.Runtime.CompilerServices.CallSite<System.Func<System.Runtime.CompilerServices.CallSite,System.Object,System.Int32>>.Target
IL_0038: ldsfld UserQuery+MyClassParent+<>o__4.<>p__0
IL_003D: ldarg.0
IL_003E: ldstr "ID"
IL_0043: call UserQuery+MyClassParent.ReadProperty
IL_0048: callvirt System.Func<System.Runtime.CompilerServices.CallSite,System.Object,System.Int32>.Invoke
IL_004D: stloc.0
IL_004E: br.s IL_0050
IL_0050: ldloc.0
IL_0051: ret
MyClassParent.set_ID:
IL_0000: nop
IL_0001: ldarg.0
IL_0002: ldstr "ID"
IL_0007: ldarg.1
IL_0008: box System.Int32
IL_000D: call UserQuery+MyClassParent.WriteProperty
IL_0012: pop
IL_0013: ret
答案 1 :(得分:0)
这是解决方案:
private void CreateProperty(TypeBuilder typeBuilder, string propertyName, Type propertyType)
{
PropertyBuilder propertyBuilder = typeBuilder.DefineProperty(propertyName, PropertyAttributes.HasDefault, propertyType, null);
MethodBuilder getPropMthdBldr = typeBuilder.DefineMethod("get_" + propertyName, MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig, propertyType, Type.EmptyTypes);
ILGenerator getIl = getPropMthdBldr.GetILGenerator();
string methodName = "ReadProperty" + propertyType.Name;
getIl.Emit(OpCodes.Ldarg_0);
getIl.Emit(OpCodes.Ldstr, propertyName);
getIl.Emit(OpCodes.Call, typeof(MyClassParent).GetMethod("ReadProperty"));
getIl.Emit(OpCodes.Ret);
propertyBuilder.SetGetMethod(getPropMthdBldr);
}