【问题标题】:How to Emit code to assign value/reference to static field of class by calling it's constructor?如何通过调用其构造函数来发出代码以将值/引用分配给类的静态字段?
【发布时间】:2015-05-20 16:39:44
【问题描述】:

(我的代码有点乱七八糟的 C# 和 VB.NET) 我正在尝试发出如下所示的类:

public class SWTTFields
{
    private string fieldName;
    private int startPosition;
    private int endPosition;

    public static readonly SWTTFields ISO = new SWTTFields("ISO", 1, 2);
    public static readonly SWTTFields EPC = new SWTTFields("EPC", 3, 4);

    private SWTTFields(String fieldName, Int32 startPositon, Int32 endPositon)
    {
        this.fieldName = fieldName;
        this.startPosition = startPositon;
        this.endPosition = endPositon;
    }
}

但是,我在将引用分配给两个静态成员时很累。 到目前为止,我明白了这一点(下面的代码在 VB.NET 中,但我很乐意接受 VB.NET 或 C# 中的答案):

Dim typeBuilder As TypeBuilder = GetTypeBuilder()

'Definition of three private variables
'TODO: you need one more private field that would represent "Bank" particular field belongs to

'Private String fieldName
Dim fieldName As FieldBuilder = typeBuilder.DefineField("fieldName",
                                                         GetType(String),
                                                            FieldAttributes.Private)
'Private Int32 startPosition
Dim startPosition As FieldBuilder = typeBuilder.DefineField("startPosition",
                                                            GetType(Int32),
                                                              FieldAttributes.Private)
'Private Int32 endPosition
Dim endPosition As FieldBuilder = typeBuilder.DefineField("endPosition",
                                                          GetType(Int32), FieldAttributes.Private)

'Type is taken from the current TypeBuilder
Dim ISO As FieldBuilder = typeBuilder.DefineField("ISO", typeBuilder.GetType, FieldAttributes.Public)                                                           
Dim EPC As FieldBuilder = typeBuilder.DefineField("EPC", typeBuilder.GetType, FieldAttributes.Public)

'Constructor parameters are
Dim constructorParams() As Type = {GetType(String), GetType(Int32), GetType(Int32)}

'constructor for the class 
Dim ctorBuilder As ConstructorBuilder = typeBuilder.DefineConstructor(MethodAttributes.Public Or
                                                                     MethodAttributes.SpecialName Or
                                                                     MethodAttributes.RTSpecialName,
                                                                     CallingConventions.Standard,
                                                                     constructorParams)

Dim objType As Type = Type.GetType("System.Object")
'pulls out info about Object constructor. It will be called later 
Dim objCtor As ConstructorInfo = objType.GetConstructor(Type.EmptyTypes)

'Generating code (some of the code and comments came from ConstructorBuilder class)
Dim ctorIL As ILGenerator = ctorBuilder.GetILGenerator()

'place "this" on the stack 
ctorIL.Emit(OpCodes.Ldarg_0)
'Create instance of System.Object by invokign its ctor
ctorIL.Emit(OpCodes.Call, objCtor)

'store fieldName parameter 
ctorIL.Emit(OpCodes.Ldarg_0)
ctorIL.Emit(OpCodes.Ldarg_1)
ctorIL.Emit(OpCodes.Stfld, fieldName)

'store startPosition
ctorIL.Emit(OpCodes.Ldarg_0)
ctorIL.Emit(OpCodes.Ldarg_2)
ctorIL.Emit(OpCodes.Stfld, startPosition)

'stored endPosition
ctorIL.Emit(OpCodes.Ldarg_0)
ctorIL.Emit(OpCodes.Ldarg_3)
ctorIL.Emit(OpCodes.Stfld, endPosition)
'Done. Return
ctorIL.Emit(OpCodes.Ret)

【问题讨论】:

    标签: c# .net vb.net cil reflection.emit


    【解决方案1】:

    我自己没有使用过TypeBuilder,所以这更像是一个提示而不是完整的代码,但基本上我相信你想要TypeBuilder.DefineTypeInitializer,并在那里执行任务。

    换句话说,就其静态成员而言,将类想象成如下所示:

    public class SWTTFields
    {
        public static readonly SWTTFields ISO;
        public static readonly SWTTFields EPC;
    
        static SWTTFields()
        {
            ISO = new SWTTFields("ISO", 1, 2);
            EPC = new SWTTFields("EPC", 3, 4);
        }
    }
    

    (由于静态构造函数的不同,这并不完全等同于原始代码,但它已经足够接近了。)

    看起来您已经知道如何为该类型初始化器主体生成相关的 IL - 只需将其视为任何其他方法/构造器主体即可。

    【讨论】:

    • 请原谅我的无知,但我看不出TypeBuilder.DefineTypeInitializerTypeBuilder.DefineConstructor 有何不同?
    • @newprint: DefineTypeInitializer 创建一个静态构造函数。 DefineConstructor 创建实例构造函数。
    • @John Skeet 谢谢。命名有点混乱。 TypeBuilder.DefineStaticConstructor 听起来会更好。
    • @newprint:嗯,它真的是一个类型初始化器——“静态构造函数”是 C# 术语,而不是 CLR 术语。并且取决于该类是否具有beforefieldinit 标志,它会根据您的原始代码充当类型初始化程序,或者根据我的答案中的代码充当静态构造函数。有细微的差别,但这个名字在上下文中是有意义的,IMO。
    猜你喜欢
    • 1970-01-01
    • 2023-04-04
    • 1970-01-01
    • 2014-02-25
    • 1970-01-01
    • 1970-01-01
    • 2011-02-28
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多