2011-01-03 7 views
6

これは学習の練習です。私はFooと文字列を取り、Aプロパティを設定するメソッドを作成しました。私は、リフレクター分解を使用して、次の放射コードを作成しました。解体は、次のようになります。DynamicMethodを作成してプロパティに値を割り当てますか?

.method private hidebysig static void Spork(class ConsoleTesting.Foo f, string 'value') cil managed 
{ 
    .maxstack 8 
    L_0000: ldarg.0 
    L_0001: ldarg.1 
    L_0002: callvirt instance void ConsoleTesting.Foo::set_A(string) 
    L_0007: ret 
} 

[OK]を、ので、私はその後、私のEMITコードをモデル化:私はこの例外を取得してい

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Reflection; 
using System.Reflection.Emit; 


namespace ConsoleTesting 
{ 
    class Foo 
    { 
     public string A { get; set; } 
    } 

    class Program 
    { 
     static Action<Foo, string> GenMethodAssignment(string propName) 
     { 
      MethodInfo setMethod = typeof(Foo).GetMethod("get_" + propName); 
      if (setMethod == null) 
       throw new InvalidOperationException("no property setter available"); 

      Type[] argTypes = new Type[] { typeof(Foo), typeof(String) }; 
      DynamicMethod method = new DynamicMethod("__dynamicMethod_Set_" + propName, null, argTypes, typeof(Program)); 
      ILGenerator IL = method.GetILGenerator(); 
      IL.Emit(OpCodes.Ldarg_0); 
      IL.Emit(OpCodes.Ldarg_1); 
      IL.Emit(OpCodes.Callvirt, setMethod); 
      IL.Emit(OpCodes.Ret); 
      method.DefineParameter(1, ParameterAttributes.In, "instance"); 
      method.DefineParameter(2, ParameterAttributes.In, "value"); 

      Action<Foo, string> retval = (Action<Foo, string>)method.CreateDelegate(typeof(Action<Foo, string>)); 
      return retval; 
     } 

     static void Main(string[] args) 
     { 
      Foo f = new Foo(); 
      var meth = GenMethodAssignment("A"); 
      meth(f, "jason"); 
      Console.ReadLine(); 
     } 
    } 

JIT Compiler encountered an internal limitation. 

krunkがあることは何私はそれをどのように修正するのですか?

EDIT:

私はターゲットメソッドがプライベートであるので、多分それはだと思ったが、私はそうはわかりません。 DynamicMethod MSDN page

次のコード例は、論理的に型に関連付けられたDynamicMethodを作成します。この関連付けによって、そのタイプのプライベートメンバーにアクセスできます。

+0

"get_"メソッドにアクセスしています。これはあなたの投稿の入力ミスですか?名前でプロパティにアクセスし、PropertyInfoオブジェクトでGetSetMethod()メソッドを使用できます。この方法では、 "get_"と "set_"というC#の規約に頼っているわけではありません。 –

+0

しかし、今私は打ち間違いを訂正しました。 ILにはAの代わりにAStrが含まれていました。なぜなら私はこのポストの目的のためにプロパティの名前を変更したからです。 – Amy

+0

ああ、私はあなたのコメントの最初の文を誤解しました。あなたは絶対に正しいです。 – Amy

答えて

2

私はそれを理解しました。

IL.Emit(OpCodes.Call, setMethod); 

IL.Emit(OpCodes.Callvirt, setMethod); 

を変更すると、それを修正しました。私はなぜ分解がCallVirtを示したのか分かりませんが、ええ。

+0

.NETのどのバージョンですか? .NET4では、インスタンス上にあるメソッドを呼び出そうとするセキュリティ例外が発生します。 –

1

実行する.NETのバージョンは何ですか?式ツリーからデリゲートをコンパイルする方がはるかに簡単です。

+0

.Net 3.5では、式ツリーで代入を行うことはできません。 – Amy

+0

彼がやっているのは、.NET 3.5でもそれを行うことができるセッターメソッドを呼び出しているからです。単に 'Expression.Call(target、setMethod、valueExpression)'を実行してください。それはtostringに 'target.set_Property(value)'と表示されますが、動作します。 –

4

興味深い問題です。まず、あなたができることはほとんどありません。セッターのデリゲートだけが必要な場合は、Delegate.CreateDelegateを使用できます。

Delegate.CreateDelegate(typeof(Action<Foo, string>),typeof(Foo).GetProperty("A").GetSetMethod()) as Action<Foo,String>; 

あなたは式ツリーを使用することができますし、私は強くDynamicMethodの上にそれらを学ぶお勧めします3.5+ .NETを使用している場合、彼らは.NET 3.5での使用が限られているし、ほとんどなし.NET 4.(TypeBuilderはまだ非常に便利ですしかし)。 .NET 4で

var targetExpression = Expression.Parameter(typeof(Foo),"target"); 
var valueExpression = Expression.Parameter(typeof(string),"value"); 
var expression = Expression.Lambda<Action<Foo,string>>(
     Expression.Call(
      targetExpression, 
      typeof(Foo).GetProperty("A").GetSetMethod(), 
      valueExpression 
    ), 
     targetExpression, 
     valueExpression 
); 

あなたはExpression.Assignを使用することによって、わずかにきれいになるためにそれを書くことができますが、それははるかに良いではありません。

最後に、ILで実際にやりたければ、これが機能します。

 DynamicMethod method = new DynamicMethod("Setter", typeof(void), new[] { typeof(Foo), typeof(string) }, true); 
     var ilgen = method.GetILGenerator(); 
     ilgen.Emit(OpCodes.Ldarg_0); 
     ilgen.Emit(OpCodes.Ldarg_1); 
     ilgen.Emit(OpCodes.Callvirt, typeof(Foo).GetProperty("A").GetSetMethod()); 
     ilgen.Emit(OpCodes.Ret); 
     var action = method.CreateDelegate(typeof(Action<Foo,string>)) as Action<Foo,string>; 

は、私はあなたの問題はあなたが現在setメソッドは、実際にエラーがこの行:: MethodInfo setMethod = typeof(Foo).GetMethod("get_" + propName);

私は、パラメータの属性が割り当てられたことがない上にあるgetMethodで呼び出しているということだと思うが、それはあってもよいです問題もあります。

関連する問題