首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >用TypeBuilder自引用类属性

用TypeBuilder自引用类属性
EN

Stack Overflow用户
提问于 2022-07-17 15:33:31
回答 1查看 29关注 0票数 0

我尝试构建运行时类型生成器,但是我遇到了自引用类型属性的鸡蛋和鸡问题。我正在使用TypeBuilder,基本上我要传递一个属性名称及其类型的列表,然后生成一个类型--只要在创建时知道类型,它就能正常工作。然而,我想要实现这个基本概念

代码语言:javascript
复制
  public class Person
  {
      public string Name { get; set; }
      public Person Child { get; set; }
  }

我几乎被困住了。我如何告诉TypeBuilder我想要一个尚未创建的类型的属性?CLR是怎么做到的?

我的当前代码

代码语言:javascript
复制
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);
    }
}
EN

回答 1

Stack Overflow用户

发布于 2022-07-20 13:30:08

CreateProperty允许通过为field.FieldType设置null的方式传递field.FieldType,在这种情况下,TypeBuilder tb类型将用作属性类型。

所以把null传递给FieldType和everything 应起作用

代码语言:javascript
复制
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 TypeToTest
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/73013082

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档