如何修改此代码以使用 getter/setter?
How to adapt this code to use getter/setter?
我尝试修改此代码但失败了。这是来自 C# 语言汇编的动态 class 生成器。我不能使用 DynamicObjects,因为 RDLC 报告不适用于 System.Dynamic 中的 none class,但可以很好地处理由程序集生成的 class。
我想要做的是将 属性 定义从私有变量更改为方法 get 和 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);
}
}
}
这就是如何使用那个美妙的 class 生成器
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();
}
}
}
如何将要生成的代码添加到目标中 class,就像这样
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
这是解决方案:
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);
}
我尝试修改此代码但失败了。这是来自 C# 语言汇编的动态 class 生成器。我不能使用 DynamicObjects,因为 RDLC 报告不适用于 System.Dynamic 中的 none class,但可以很好地处理由程序集生成的 class。
我想要做的是将 属性 定义从私有变量更改为方法 get 和 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);
}
}
}
这就是如何使用那个美妙的 class 生成器
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();
}
}
}
如何将要生成的代码添加到目标中 class,就像这样
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
这是解决方案:
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);
}