我尝试构建运行时类型生成器,但是我遇到了自引用类型属性的鸡蛋和鸡问题。我正在使用TypeBuilder,基本上我要传递一个属性名称及其类型的列表,然后生成一个类型--只要在创建时知道类型,它就能正常工作。然而,我想要实现这个基本概念
public class Person
{
public string Name { get; set; }
public Person Child { get; set; }
}我几乎被困住了。我如何告诉TypeBuilder我想要一个尚未创建的类型的属性?CLR是怎么做到的?
我的当前代码
public class FieldDescription
{
public string FieldName { get; set; }
public Type FieldType { get; set; }
}
public static class CustomTypeBuilder
{
public static Type CompileResultType(List<FieldDescription> fields, string TypeName)
{
TypeBuilder tb = GetTypeBuilder(TypeName);
ConstructorBuilder constructor = tb.DefineDefaultConstructor(MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName);
foreach (var field in fields)
CreateProperty(tb, field);
Type objectType = tb.CreateType();
return objectType;
}
private static TypeBuilder GetTypeBuilder(string typeSignature)
{
var an = new AssemblyName(typeSignature);
AssemblyBuilder assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(an, AssemblyBuilderAccess.Run);
ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule("MyModule");
TypeBuilder tb = moduleBuilder.DefineType(typeSignature,
TypeAttributes.Public |
TypeAttributes.Class |
TypeAttributes.AutoClass |
TypeAttributes.AnsiClass |
TypeAttributes.BeforeFieldInit |
TypeAttributes.AutoLayout,
null);
FieldBuilder fieldBuilder = tb.DefineField("_ToStringValue", typeof(string), FieldAttributes.Private);
return tb;
}
private static void CreateProperty(TypeBuilder tb, FieldDescription field)
{
string propertyName = field.FieldName;
Type propertyType = field.FieldType ?? tb;
FieldBuilder fieldBuilder = tb.DefineField("_" + propertyName, propertyType, FieldAttributes.Private);
PropertyBuilder propertyBuilder = tb.DefineProperty(propertyName, PropertyAttributes.HasDefault, propertyType, null);
MethodBuilder getPropMthdBldr = tb.DefineMethod("get_" + propertyName, MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig | MethodAttributes.Virtual, propertyType, Type.EmptyTypes);
ILGenerator getIl = getPropMthdBldr.GetILGenerator();
getIl.Emit(OpCodes.Ldarg_0);
getIl.Emit(OpCodes.Ldfld, fieldBuilder);
getIl.Emit(OpCodes.Ret);
MethodBuilder setPropMthdBldr =
tb.DefineMethod("set_" + propertyName,
MethodAttributes.Public |
MethodAttributes.SpecialName |
MethodAttributes.HideBySig | MethodAttributes.Virtual,
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);
}
}发布于 2022-07-20 13:30:08
CreateProperty允许通过为field.FieldType设置null的方式传递field.FieldType,在这种情况下,TypeBuilder tb类型将用作属性类型。
所以把null传递给FieldType和everything 应起作用
var compileResultType = CustomTypeBuilder.CompileResultType(new List<FieldDescription>
{
new() { FieldName = "Test1", FieldType = typeof(string) },
new() { FieldName = "Test2", FieldType = null } // property of the type being created
},
"TypeToTest");
var instance = Activator.CreateInstance(compileResultType);
var test1PI = compileResultType.GetProperty("Test1");
var test2PI = compileResultType.GetProperty("Test2");
test1PI.SetValue(instance, "test");
test2PI.SetValue(instance, instance);
Console.WriteLine(test1PI.GetValue(instance)); // prints test
Console.WriteLine(test2PI.GetValue(instance)); // prints TypeToTesthttps://stackoverflow.com/questions/73013082
复制相似问题