Silverlight 3.0 C#-使用Methodbuilder创建一个SET方法,并使用ILGenerator和Emit添加MSIL

Silverlight 3.0 C#-使用Methodbuilder创建一个SET方法,并使用ILGenerator和Emit添加MSIL,c#,silverlight,silverlight-3.0,cil,C#,Silverlight,Silverlight 3.0,Cil,呵呵 我有一些构建新类型运行时的代码,它使用MethodBuilder设置GET和SET方法。(这是网络上的一个例子,多亏了写这篇文章的那个人,我不幸地把裁判丢给了他,但他在我的脑海里) 我以这种方式向类添加了一个方法 MethodAttributes GetSetAttr = MethodAttributes.Public | MethodAttributes.HideBySig; // Define the "get" accessor method for

呵呵

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

我以这种方式向类添加了一个方法

    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更改为更复杂的内容,因此我编写了此测试代码

公共类客户 { 私有字符串\u名称; 公共字符串名 { 获取{return\u name;} 集合{ if(string.IsNullOrEmpty(value)) { 抛出新的ValidationException(“请设置一个值”); } _名称=值; } } 公共字符串lastname{get;set;} }

编译并使用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 
}
因此,任务是将其实现到集合EMIT代码中

                // Again some Intermediate Language stuff...
                ILGenerator currSetIL = currSetPropMthdBldr.GetILGenerator();
这就是我的不足之处,我无法让它发挥作用。我不能“仅仅”复制代码,而且我的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行上,这些红色下划线给出了DE错误

  • Bool=“)expected”
  • [mscorlib]系统=“;预期”
  • :=“。应为”
  • 最后)给出“无效” 表达式术语字符串“
我想知道为什么我不能使用反射器,代码应该可以吗?还是

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

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

Peww,一个很长的问题,我希望这里的一切都准备好了

问候 重新装载

currSetIL.Emit(操作码.Call bool[mscorlib]System.String::IsNullOrEmpty(String);//Call bool[mscorlib]System.String::IsNullOrEmpty(String)

您需要获取
MethodInfo
——在这种情况下:

currSetIL.EmitCall(OpCodes.Call,typeof(string).GetMethod("IsNullOrEmpty"),null);
事实上,尽管如此,我还是会为此研究
表达式
——我相信silverlight
表达式有一个
编译
,你不必学习IL


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

+1-对我来说太快了。此外,我想指出的是,你可能不想添加操作码.Nop语句,这可能是currSetIL.Emit(opcode.Call,typeof(string).GetMethod(“IsNullOrEmpty”)-更短,同样的事情?@Benjamin:是的,绝对是“Nop”是调试器的总开销,可以删除。好的,谢谢你的快速回答,(是的,nop是开销:-),但我接受了它,以显示从MSIL到EMIT的1:1转换,命令),所以简言之,有没有工具或东西可以让我从MSIL到EMIT sting。MSIL代码中还有许多其他行需要转换?或者更好的是,我可以直接向generateed类型添加一个方法。类似于这个属性的东西。SetSetMethod(MyMethod);//这是行不通的,因为SetMethod需要一个Methodbuilder而不是一个方法,所以我可以基于另一个方法创建一个吗?这会解决问题的。嗨,大家好,经过一番考虑后,我决定用另一种方法来解决这个问题。(使用动态)这更透明、更容易。谢谢你的评论和回复。关于重新载入评论;好吧,这将是一个相当手工的翻译。不过,说真的,我认为您可以通过
表达式
(尤其是在新对象的情况下)来完成所有这一切。你有一个你想要实现的例子吗?i、 e.你能发布你想要的C#等价物吗?
        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)
currSetIL.EmitCall(OpCodes.Call,typeof(string).GetMethod("IsNullOrEmpty"),null);