Silverlight 3.0 C# - 使用 Methodbuilder 创建 SET 方法,并使用 ILGenerator 和 Emit 添加 MSIL
Hej All
我有一些构建新 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; } 放 { if ( string.IsNullOrEmpty( 值 ) ) { throw new ValidationException("请设置一个值"); } _名称=值; } } 公共字符串姓氏{获取;放; } }
编译然后使用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, 字段); 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 = ") Expected"
- [mscorlib]System = ";预期"
- :: = ".预期"
- 并且最后一个 ) 给出了“无效” 表达式术语字符串”
我想知道为什么我不能使用反射器,代码应该没问题?或者?
解决方案是找到一个程序/方法来显示可在 EMIT 语句中使用的 MSIL 代码。
这只是一个示例,所以代码会改变,所以这不是一个回答正确代码的解决方案(尽管如此,让示例工作会很高兴),而是从 C# 获取正确 MSIL 的更永久的“方法”,这是
一个很长的问题,我希望我有。 这里的一切。
问候 重新加载
Hej All
I have some code that builds a new TYPE runtime, it sets the GET and SET method using MethodBuilder. (Its an exampel from the web, and thanks to the Guy, that wrote it, i unfortantly lost the ref. to him, but he is in my thoughts)
TypeBuilder typeBuilder = module.DefineType("MyClass", TypeAttributes.Public | TypeAttributes.Class);
I add a method to the class this way.
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);
It works fine, i would however like to change the setmethod to something more complex, so i write this test code.
public class Customer
{
private string _name;
public string name
{
get { return _name; }
set {
if ( string.IsNullOrEmpty( value ) )
{
throw new ValidationException("Please set a value");
}
_name = value;
}
}
public string lastname { get; set; }
}
Compile and then use Reflector to get the 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
}
So the task is to implement it into the SET EMIT code.
// 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);
This, is where i come short, i cant get it to work. It seams that i can's "just" copy the code over, and my MSIL skills are limited. hereunder is my error.
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)
On the 3 line, these red underlines give thede errors...
- Bool = ") Expetced"
- [mscorlib]System = "; expected"
- :: = ". expected"
- and the last ) gives "invalid
expression term string"
I wonder why i cant use reflector, the code should be ok? or?
The solution it to find a program / Method that displays MSIL code that can be used in the EMIT statement.
This is just an example so the code will change, so it's not a solution to answer the correct code (allthou it will be nice to get the example working) but a more permenent "way" of getting the correct MSIL from C#.
Peww, a long question, i hope i have everything in here.
Regards
ReLoad
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
您需要获取
MethodInfo
- 在这种情况下:实际上,我会为此研究
Expression
- 我相信有一个用于 silverlightCompile
>Expression,并且您不必学习 IL!请注意,如果存在多个重载,您通常需要做更多的工作来获取
MethodInfo
(恰好< code>string.IsNullOrEmpty 很容易使用)。另外,请注意,“实例”方法应使用OpCodes.Callvirt
;静态方法(如本例)应使用OpCodes。调用
。You need to get the
MethodInfo
- in this case:Actually, though, I'd be looking into
Expression
for this - I believe there is aCompile
for silverlightExpression
, and you don't have to learn IL!Note that if there are multiple overloads you generally have to do a lot more work to get the
MethodInfo
(it just happens thatstring.IsNullOrEmpty
is easy to use). Also, note that "instance" methods should useOpCodes.Callvirt
; static methods (like this one) should useOpCodes.Call
.