English 中文(简体)
Silverlight 3.0 C# - Using Methodbuilder to create a SET method, and adding the MSIL with ILGenerator and Emit
原标题:

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

最佳回答

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.

问题回答

暂无回答




相关问题
Anyone feel like passing it forward?

I m the only developer in my company, and am getting along well as an autodidact, but I know I m missing out on the education one gets from working with and having code reviewed by more senior devs. ...

NSArray s, Primitive types and Boxing Oh My!

I m pretty new to the Objective-C world and I have a long history with .net/C# so naturally I m inclined to use my C# wits. Now here s the question: I feel really inclined to create some type of ...

C# Marshal / Pinvoke CBitmap?

I cannot figure out how to marshal a C++ CBitmap to a C# Bitmap or Image class. My import looks like this: [DllImport(@"test.dll", CharSet = CharSet.Unicode)] public static extern IntPtr ...

How to Use Ghostscript DLL to convert PDF to PDF/A

How to user GhostScript DLL to convert PDF to PDF/A. I know I kind of have to call the exported function of gsdll32.dll whose name is gsapi_init_with_args, but how do i pass the right arguments? BTW, ...

Linqy no matchy

Maybe it s something I m doing wrong. I m just learning Linq because I m bored. And so far so good. I made a little program and it basically just outputs all matches (foreach) into a label control. ...

热门标签