2

ヘジ・オール

新しい 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 をより複雑なものに変更したいので、このテスト コードを記述します。

public class Customer { プライベート文字列 _name; パブリック文字列名 { get { return _name; } set { if ( string.IsNullOrEmpty( value ) ) { throw new ValidationException("値を設定してください"); } _name = 値; } } パブリック文字列の姓 { get; 設定; } }

コンパイルし、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, field);
                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 = ") 期待される"
  • [mscorlib]システム = "; 期待"
  • :: = "。期待"
  • そして最後の ) は「無効な式用語文字列」を与える

リフレクターを使用できないのはなぜでしょうか。コードは問題ないはずですか? また?

EMITステートメントで使用できるMSILコードを表示するプログラム/メソッドを見つけることが解決策です。

これは単なる例であるため、コードは変更されるため、正しいコードに回答するための解決策ではありません (例を機能させることは素晴らしいことです) が、C# から正しい MSIL を取得するためのより恒久的な "方法" です。

Peww、長い質問です。ここにすべてが揃っていることを願っています。

よろしくリロード

4

1 に答える 1

3

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

MethodInfoこの場合、-を取得する必要があります。

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

しかし、実際には、Expressionこれを調べていると思います。SilverlightCompile用があるExpressionと思います。ILを学ぶ必要はありません。

複数のオーバーロードがある場合は、通常、を取得するためにさらに多くの作業を行う必要があることに注意してくださいMethodInfo(これstring.IsNullOrEmptyは簡単に使用できます)。また、「インスタンス」メソッドはOpCodes.Callvirt;を使用する必要があることに注意してください。静的メソッド(このような)はを使用する必要がありますOpCodes.Call

于 2010-01-15T12:59:42.897 に答える