C# 反思:如何初始化在 TypeBuilder 中动态创建的字段?

发布于 2024-12-10 00:33:06 字数 1470 浏览 0 评论 0原文

我正在创建一个动态 dll 来保存从我的数据库创建的自定义对象。我可以按照我想要的方式创建字段,但是我不明白如何调用构造函数。对于最终生成的结果,我想要:

public class Countries
{
    public Countries() { }
    public static readonly ReferenceObject USA = new ReferenceObject(120);
    public static readonly ReferenceObject CAN = new ReferenceObject(13);
    public static readonly ReferenceObject MEX = new ReferenceObject(65);
    ... //These would be populated from the database
}

我得到的是

public class Countries
{
    public Countries() { }
    public static readonly ReferenceObject USA;
    public static readonly ReferenceObject CAN;
    public static readonly ReferenceObject MEX;
    ...
}

如何将值设置为新的初始化对象?

AppDomain domain = AppDomain.CurrentDomain;

AssemblyName aName = new AssemblyName("DynamicEnums");
AssemblyBuilder ab = domain.DefineDynamicAssembly(aName, AssemblyBuilderAccess.Save);

ModuleBuilder mb = ab.DefineDynamicModule(aName.Name, aName.Name + ".dll");

foreach(ReferenceType rt in GetTypes())
{
    TypeBuilder tb = mb.DefineType(rt.Name, TypeAttributes.Public);

    foreach (Reference r in GetReferences(rt.ID))
    {
        string name = NameFix(r.Name);

        FieldBuilder fb = tb.DefineField(name, typeof(ReferenceObject), FieldAttributes.Static | FieldAttributes.Public | FieldAttributes.Literal);

        //Call constructor here... how???
    }

    types.Add(tb.CreateType());
}

ab.Save(aName.Name + ".dll");

I'm creating a dynamic dll to hold custom objects created from my database. I can create the field the way I want, however I don't understand how to call the constructor. For a final generated result, I want:

public class Countries
{
    public Countries() { }
    public static readonly ReferenceObject USA = new ReferenceObject(120);
    public static readonly ReferenceObject CAN = new ReferenceObject(13);
    public static readonly ReferenceObject MEX = new ReferenceObject(65);
    ... //These would be populated from the database
}

what I'm getting is

public class Countries
{
    public Countries() { }
    public static readonly ReferenceObject USA;
    public static readonly ReferenceObject CAN;
    public static readonly ReferenceObject MEX;
    ...
}

How do I set the values to new initialized objects?

AppDomain domain = AppDomain.CurrentDomain;

AssemblyName aName = new AssemblyName("DynamicEnums");
AssemblyBuilder ab = domain.DefineDynamicAssembly(aName, AssemblyBuilderAccess.Save);

ModuleBuilder mb = ab.DefineDynamicModule(aName.Name, aName.Name + ".dll");

foreach(ReferenceType rt in GetTypes())
{
    TypeBuilder tb = mb.DefineType(rt.Name, TypeAttributes.Public);

    foreach (Reference r in GetReferences(rt.ID))
    {
        string name = NameFix(r.Name);

        FieldBuilder fb = tb.DefineField(name, typeof(ReferenceObject), FieldAttributes.Static | FieldAttributes.Public | FieldAttributes.Literal);

        //Call constructor here... how???
    }

    types.Add(tb.CreateType());
}

ab.Save(aName.Name + ".dll");

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

自我难过 2024-12-17 00:33:06

来自我的 回答您的其他(非常相似)问题,但是:

AppDomain domain = AppDomain.CurrentDomain;

AssemblyName aName = new AssemblyName("DynamicEnums");
AssemblyBuilder ab = domain.DefineDynamicAssembly(aName, AssemblyBuilderAccess.Save);

ModuleBuilder mb = ab.DefineDynamicModule(aName.Name, aName.Name + ".dll");

// Store a handle to the ReferenceObject(int32 pValue)
// constructor.
ConstructorInfo referenceObjectConstructor = typeof(ReferenceObject).GetConstructor(new[] { typeof(int) });

foreach (ReferenceType rt in GetTypes())
{
    TypeBuilder tb = mb.DefineType(rt.Name, TypeAttributes.Public);

    // Define a static constructor to populate the ReferenceObject
    // fields.
    ConstructorBuilder staticConstructorBuilder = tb.DefineConstructor(MethodAttributes.Public | MethodAttributes.Static, CallingConventions.Standard, Type.EmptyTypes);
    ILGenerator staticConstructorILGenerator = staticConstructorBuilder.GetILGenerator();

    foreach (Reference r in GetReferences(rt.ID))
    {
        string name = r.Abbreviation.Trim();

        // Create a public, static, readonly field to store the
        // named ReferenceObject.
        FieldBuilder referenceObjectField = tb.DefineField(name, typeof(ReferenceObject), FieldAttributes.Static | FieldAttributes.Public | FieldAttributes.InitOnly);

        // Add code to the static constructor to populate the
        // ReferenceObject field:

        // Load the ReferenceObject's ID value onto the stack as a
        // literal 4-byte integer (Int32).
        staticConstructorILGenerator.Emit(OpCodes.Ldc_I4, r.ID);

        // Create a reference to a new ReferenceObject on the stack
        // by calling the ReferenceObject(int32 pValue) reference
        // we created earlier.
        staticConstructorILGenerator.Emit(OpCodes.Newobj, referenceObjectConstructor);

        // Store the ReferenceObject reference to the static
        // ReferenceObject field.
        staticConstructorILGenerator.Emit(OpCodes.Stsfld, referenceObjectField);
    }

    // Finish the static constructor.
    staticConstructorILGenerator.Emit(OpCodes.Ret);

    tb.CreateType();
}

ab.Save(aName.Name + ".dll");

Bit of a copy-pasta from my answer to your other (very similar) question, but:

AppDomain domain = AppDomain.CurrentDomain;

AssemblyName aName = new AssemblyName("DynamicEnums");
AssemblyBuilder ab = domain.DefineDynamicAssembly(aName, AssemblyBuilderAccess.Save);

ModuleBuilder mb = ab.DefineDynamicModule(aName.Name, aName.Name + ".dll");

// Store a handle to the ReferenceObject(int32 pValue)
// constructor.
ConstructorInfo referenceObjectConstructor = typeof(ReferenceObject).GetConstructor(new[] { typeof(int) });

foreach (ReferenceType rt in GetTypes())
{
    TypeBuilder tb = mb.DefineType(rt.Name, TypeAttributes.Public);

    // Define a static constructor to populate the ReferenceObject
    // fields.
    ConstructorBuilder staticConstructorBuilder = tb.DefineConstructor(MethodAttributes.Public | MethodAttributes.Static, CallingConventions.Standard, Type.EmptyTypes);
    ILGenerator staticConstructorILGenerator = staticConstructorBuilder.GetILGenerator();

    foreach (Reference r in GetReferences(rt.ID))
    {
        string name = r.Abbreviation.Trim();

        // Create a public, static, readonly field to store the
        // named ReferenceObject.
        FieldBuilder referenceObjectField = tb.DefineField(name, typeof(ReferenceObject), FieldAttributes.Static | FieldAttributes.Public | FieldAttributes.InitOnly);

        // Add code to the static constructor to populate the
        // ReferenceObject field:

        // Load the ReferenceObject's ID value onto the stack as a
        // literal 4-byte integer (Int32).
        staticConstructorILGenerator.Emit(OpCodes.Ldc_I4, r.ID);

        // Create a reference to a new ReferenceObject on the stack
        // by calling the ReferenceObject(int32 pValue) reference
        // we created earlier.
        staticConstructorILGenerator.Emit(OpCodes.Newobj, referenceObjectConstructor);

        // Store the ReferenceObject reference to the static
        // ReferenceObject field.
        staticConstructorILGenerator.Emit(OpCodes.Stsfld, referenceObjectField);
    }

    // Finish the static constructor.
    staticConstructorILGenerator.Emit(OpCodes.Ret);

    tb.CreateType();
}

ab.Save(aName.Name + ".dll");
稍尽春風 2024-12-17 00:33:06

当编写一个 C# 类(其中的字段像您的示例中那样进行初始化)时,编译器所做的就是在构造函数中生成初始化代码。

这就是我认为您应该做的:使用 TypeBuilder.DefineConstructor 生成构造函数,并在内部创建代码来设置字段。

When one writes a C# class where fields are initialized like in your example, what the compiler does is generate initialization code in the constructor.

This is what I think you should do: use TypeBuilder.DefineConstructor to generate a constructor and, inside, create code to set the fields.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文