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

发布于 2024-08-18 16:34:38 字数 4385 浏览 6 评论 0原文

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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

唐婉 2024-08-25 16:34:38

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 - 我相信有一个用于 silverlight Compile >Expression,并且您不必学习 IL!

请注意,如果存在多个重载,您通常需要做更多的工作来获取 MethodInfo (恰好< code>string.IsNullOrEmpty 很容易使用)。另外,请注意,“实例”方法应使用 OpCodes.Callvirt;静态方法(如本例)应使用 OpCodes。调用

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

You need to get the MethodInfo - in this case:

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

Actually, though, I'd be looking into Expression for this - I believe there is a Compile for silverlight Expression, 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 that string.IsNullOrEmpty is easy to use). Also, note that "instance" methods should use OpCodes.Callvirt; static methods (like this one) should use OpCodes.Call.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文