Silverlight 3.0 C#-使用Methodbuilder创建一个SET方法,并使用ILGenerator和Emit添加MSIL
呵呵 我有一些构建新类型运行时的代码,它使用MethodBuilder设置GET和SET方法。(这是网络上的一个例子,多亏了写这篇文章的那个人,我不幸地把裁判丢给了他,但他在我的脑海里) 我以这种方式向类添加了一个方法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
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]系统=“;预期”
- :=“。应为”
- 最后)给出“无效” 表达式术语字符串“
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);