2016-11-03 9 views
0

私は動的ラッパーを作成しようとしていますが、私の間違いを忘れることはありません。ここで は、私が得たものである:IL Emit - プロパティのリダイレクト

単純なデータクラス:

public class Data 
{ 
    public int MyProperty { get; set; } = 42; 
} 

基本クラス、リダイレクトのための場を提供する:

public class WrapperBase<T> where T : new() 
    { 
     public WrapperBase() 
     { 
      Field = new T(); 
     } 
     public T Field { get; set; } 
     public void Foo(); 
    } 

リダイレクトベースを使用してクラス:

public class SomeDynamicClass : WrapperBase<Data> { } 

と、それを使用してクラス:

public class User 
{ 
    public User() 
    { 
     Content = MyFactory.Create<SomeDynamicClass>(); 
    } 
    public object Content { get; set; } 
} 

これは私が工場を作成したいものです。

public class DesiredResult : SomeDynamicClass 
{ 
    public int MyProperty 
    { 
     get { return Field.MyProperty; } 
     set 
     { 
      Field.MyProperty = value; 
      Foo(); 
     } 
    } 
} 

私はILコードをチェックし、それを再コーディングしようとしたが、私のミスがありました見つけることができません。ここで私はこれまで得たものである:私は無効なILコードを生成していますように

public class Factory 
{ 
    private const String NAMESPACE = "vmproxy.{0}"; 
    public object Create<T>() where T : class 
    { 
     AssemblyName an = new AssemblyName(); 
     an.Name = Guid.NewGuid().ToString(); 
     AppDomain ad = AppDomain.CurrentDomain; 
     AssemblyBuilder ab = ad.DefineDynamicAssembly(an, AssemblyBuilderAccess.Run); 

     var _mb = ab.DefineDynamicModule(an.Name); 
     var fieldProp = typeof(T).GetProperty("Field"); 
     var modelType = typeof(T).GetProperty("Field").PropertyType; 
     var name = typeof(T).Name; 
     var tb = _mb.DefineType(String.Format(NAMESPACE, name), TypeAttributes.Public | TypeAttributes.Class, typeof(T)); 


     foreach (var property in modelType.GetProperties()) 
     { 
      PropertyBuilder prop = tb.DefineProperty(property.Name, PropertyAttributes.None, property.PropertyType, null); 
      MethodBuilder meth = tb.DefineMethod("get_" + property.Name, 
                 MethodAttributes.Public | 
                 MethodAttributes.SpecialName | 
                 MethodAttributes.Virtual | 
                 MethodAttributes.HideBySig, 
                 property.PropertyType, Type.EmptyTypes); 
      ILGenerator ilGen = meth.GetILGenerator(); 
      Label endOfMethod = ilGen.DefineLabel(); 
      ilGen.Emit(OpCodes.Ldarg_0); 
      //ilGen.Emit(OpCodes.Call, fieldProp.GetGetMethod()); 
      ilGen.EmitCall(OpCodes.Call, fieldProp.GetGetMethod(), null); 
      //ilGen.Emit(OpCodes.Callvirt, property.GetGetMethod()); 
      ilGen.EmitCall(OpCodes.Callvirt, property.GetGetMethod(),null); 
      ilGen.Emit(OpCodes.Stloc_0); 
      ilGen.Emit(OpCodes.Br_S, endOfMethod); 
      ilGen.MarkLabel(endOfMethod); 
      ilGen.Emit(OpCodes.Ldloc_0); 
      ilGen.Emit(OpCodes.Ret); 
      prop.SetGetMethod(meth); 

      //meth = tb.DefineMethod("set_" + property.Name, 
      //        MethodAttributes.Public | 
      //        MethodAttributes.SpecialName | 
      //        MethodAttributes.Virtual | 
      //        MethodAttributes.HideBySig, 
      //        null, new Type[] { property.PropertyType }); 
      //ilGen = meth.GetILGenerator(); 
      //ilGen.Emit(OpCodes.Ldarg_0); 
      //TBD... 
      break; 
     } 

     return Activator.CreateInstance(tb.CreateType()); 
    } 

は思え...作成されたILコードをチェックする方法はあり...

編集:?IL私が作成しようとしていますコード:

.method public hidebysig specialname instance int32 
      get_IntProp() cil managed 
    { 
     // Code size  17 (0x11) 
     .maxstack 1 
     .locals init ([0] int32 V_0) 
     IL_0000: nop 
     IL_0001: ldarg.0 
     IL_0002: call  instance !0 class FactoryWrapper.WrapperBase`1<class FactoryWrapper.Data>::get_Field() 
     IL_0007: callvirt instance int32 FactoryWrapper.Data::get_IntProp() 
     IL_000c: stloc.0 
     IL_000d: br.s  IL_000f 
     IL_000f: ldloc.0 
     IL_0010: ret 
    } // end of method DerivedClass3::get_IntProp 



.method public hidebysig specialname instance void 
     set_IntProp(int32 'value') cil managed 
{ 
    // Code size  27 (0x1b) 
    .maxstack 8 
    IL_0000: nop 
    IL_0001: ldarg.0 
    IL_0002: call  instance !0 class FactoryWrapper.WrapperBase`1<class FactoryWrapper.Data1::get_Field() 
    IL_0007: ldarg.1 
    IL_0008: callvirt instance void FactoryWrapper.Data::set_IntProp(int32) 
    IL_000d: nop 
    IL_000e: ldarg.0 
    IL_0014: callvirt instance void class FactoryWrapper.WrapperBase`1<class FactoryWrapper.Data1>::Foo() 
    IL_0019: nop 
    IL_001a: ret 
} // end of method DerivedClass3::set_IntProp 

編集:

"オフセット0x000cで 不明なローカルvariablenumber" を受信します私はアイデアを得た後は
+0

ILを確認するためにどのツールを使用していますか?もし私があなただったら私はILDASMを使います。あなたがビジュアルスタジオを持っているなら、ボーナスは既にあなたのシステムにあります。 – Botonomous

+1

'AssemblyBuilderAccess.RunAndSave'を使用して、あなたのアセンブリを保存してからPEVerifyを実行したり、逆アセンブルしたりして、間違っていることを確認してください。 (明らかに、実稼働環境にデプロイする際に節約ビットをスタブすることはできますが、デバッグ段階では非常に重要です)。 –

+0

もちろん、私は生成されたassemlbyを保存しようとするとILdasm ... – Jaster

答えて

1

は、答えは単純明快だった:

 ILGenerator ilGen = meth.GetILGenerator(); 

     ilGen.Emit(OpCodes.Ldarg_0); 
     ilGen.EmitCall(OpCodes.Call, fieldProp.GetGetMethod(), null); 
     ilGen.EmitCall(OpCodes.Callvirt, property.GetGetMethod(), null); 
     ilGen.Emit(OpCodes.Ret); 

     prop.SetGetMethod(meth); 

私は必要とさえ間違っているように見えるされていない多くのスタックopperations、への道を含まILDASMから使用するコード。そのコードがうまくいく理由はありません...私が投稿したものは、魅力のように機能します。

+0

クールです。 ILをデバッグモードで表示していましたか? – Botonomous

+0

Nope - 脳のデバッグを計画;)VS 2015を使用してデバッグ中にILコードをどのように表示するのか? – Jaster

+0

はい、ILDASMを使用してください。 – Botonomous

関連する問題