2

全部

我有一些构建新 TYPE 运行时的代码,它使用 MethodBuilder 设置 GET 和 SET 方法。(这是网络上的一个例子,多亏了写它的那个人,我很遗憾地把裁判丢给了他,但他在我的脑海里)

TypeBuilder typeBuilder = module.DefineType("MyClass", TypeAttributes.Public | TypeAttributes.Class);

我以这种方式向类添加方法。

    MethodAttributes GetSetAttr =
      MethodAttributes.Public |
      MethodAttributes.HideBySig;

// Define the "get" accessor method for current private field.
                MethodBuilder currGetPropMthdBldr =
                    typeBuilder.DefineMethod("get_value",
                                               GetSetAttr,
                                               typeof(string),
                                               Type.EmptyTypes);

                // Intermediate Language stuff...
                ILGenerator currGetIL = currGetPropMthdBldr.GetILGenerator();
                currGetIL.Emit(OpCodes.Ldarg_0);
                currGetIL.Emit(OpCodes.Ldfld, field);
                currGetIL.Emit(OpCodes.Ret);

                // Define the "set" accessor method for current private field.
                MethodBuilder currSetPropMthdBldr =
                    typeBuilder.DefineMethod("set_value",
                                               GetSetAttr,
                                               null,
                                               new Type[] { typeof(string) });

                // Again some Intermediate Language stuff...
                ILGenerator currSetIL = currSetPropMthdBldr.GetILGenerator();
                currSetIL.Emit(OpCodes.Ldarg_0);
                currSetIL.Emit(OpCodes.Ldarg_1);
                currSetIL.Emit(OpCodes.Stfld, field);
                currSetIL.Emit(OpCodes.Ret);



                // Last, we must map the two methods created above to our PropertyBuilder to 
                // their corresponding behaviors, "get" and "set" respectively. 
                property.SetGetMethod(currGetPropMthdBldr);
                property.SetSetMethod(currSetPropMthdBldr);

它工作正常,但是我想将 setmethod 更改为更复杂的东西,所以我编写了这个测试代码。

公共类客户{私人字符串_name; 公共字符串名称 { 获取 { 返回 _name; } set { if ( string.IsNullOrEmpty( value ) ) { throw new ValidationException("请设置一个值"); } _name = 值;} } 公共字符串姓氏 { 获取;放; } }

编译然后使用 Reflector 获取 MSIL。

.method public hidebysig specialname instance void set_name(string 'value') cil managed
{
    .maxstack 2
    .locals init (
        [0] bool CS$4$0000)
    L_0000: nop 
    L_0001: ldarg.1 
    L_0002: call bool [mscorlib]System.String::IsNullOrEmpty(string)
    L_0007: ldc.i4.0 
    L_0008: ceq 
    L_000a: stloc.0 
    L_000b: ldloc.0 
    L_000c: brtrue.s L_001a
    L_000e: nop 
    L_000f: ldstr "Please set a value"
    L_0014: newobj instance void [System.ComponentModel.DataAnnotations]System.ComponentModel.DataAnnotations.ValidationException::.ctor(string)
    L_0019: throw 
    L_001a: ldarg.0 
    L_001b: ldarg.1 
    L_001c: stfld string AnnotationTest.MainPage/Customer::_name
    L_0021: ret 
}

所以任务是将其实现到 SET EMIT 代码中。

                // Again some Intermediate Language stuff...
                ILGenerator currSetIL = currSetPropMthdBldr.GetILGenerator();
                currSetIL.Emit(OpCodes.Ldarg_0);
                currSetIL.Emit(OpCodes.Ldarg_1);
                currSetIL.Emit(OpCodes.Stfld, field);
                currSetIL.Emit(OpCodes.Ret);

这就是我的不足之处,我无法让它工作。似乎我可以“只是”复制代码,而我的 MSIL 技能是有限的。以下是我的错误。

        currSetIL.Emit(OpCodes.Nop);  //       L_0000: nop 
        currSetIL.Emit(OpCodes.Ldarg_1);  //   L_0001: ldarg.1 
        currSetIL.Emit(OpCodes.Call bool [mscorlib]System.String::IsNullOrEmpty(string);// call bool [mscorlib]System.String::IsNullOrEmpty(string)

在第 3 行,这些红色下划线给出了错误...

  • Bool = ") 已过期"
  • [mscorlib]System = "; 预期"
  • :: = ".预期"
  • 最后一个 ) 给出“无效的表达式术语字符串”

我想知道为什么我不能使用反射器,代码应该没问题?或者?

解决方案是找到一个程序/方法来显示可在 EMIT 语句中使用的 MSIL 代码。

这只是一个示例,因此代码会更改,因此它不是回答正确代码的解决方案(尽管让示例正常工作会很好),而是从 C# 获取正确 MSIL 的更持久的“方式”。

Peww,一个很长的问题,我希望我在这里拥有一切。

问候重新加载

4

1 回答 1

3

currSetIL.Emit(OpCodes.Call bool [mscorlib]System.String::IsNullOrEmpty(string);// 调用 bool [mscorlib]System.String::IsNullOrEmpty(string)

你需要得到MethodInfo- 在这种情况下:

currSetIL.EmitCall(OpCodes.Call,typeof(string).GetMethod("IsNullOrEmpty"),null);

但实际上,我会考虑Expression这个 - 我相信有一个Compilefor silverlight Expression,你不必学习 IL!

请注意,如果有多个重载,您通常需要做更多的工作才能获得MethodInfo(碰巧string.IsNullOrEmpty很容易使用)。另外,请注意“实例”方法应该使用OpCodes.Callvirt; 静态方法(像这个)应该使用OpCodes.Call.

于 2010-01-15T12:59:42.897 回答