【发布时间】:2020-10-25 17:14:18
【问题描述】:
我尝试修改此代码,但未能成功。这是来自 C# 语言程序集的动态类生成器。我不能使用 DynamicObjects,因为 RDLC 报告不适用于 System.Dynamic 中的无类,但适用于程序集生成的类。
我正在尝试将属性定义从私有变量更改为方法 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);
}
}
}
这就是那个美妙的类生成器的使用方法
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();
}
}
}
【问题讨论】:
-
让 CreateProperty 返回一个对象而不是一个 void。
-
谢谢,但是,这是什么意思……它有什么变化?
标签: c# wpf rdlc cil reflection.emit