5

C#/。Net 4.0を使用して、実行時にReflection.Emitを介してdataRowが定義されているBindingListにデータを格納しています。 (着信データの構造はさまざまで、外部ソースによって定義されています。) リフレクションとILの世界への私の最初の進出に少し苦労した後、私は自分のdataRowを値で満たし、BindingListを埋め、そして結果をグリッドに表示することができました。 データが変更されたときに、INotifyPropertyChangedインターフェイスとPropertyChangedEventHandlerを実装しようとしています。を使うこのガイドとして、私は実行するコードを持っていますが、RaisePropertyChangedイベントが発生しているように見えないか、あるいは何もしていません。 ildasm.exeを使用して動的バージョンと通常/静的バージョンを比較すると、remove_PropertyChangedメソッドとadd_PropertyChangedメソッドに大きな違いがあります。 リフレクションを介してINotifyPropertyChangedインターフェイスを実装するためのヒントや例を誰かが提供できますか。

さらに検討した結果、PropertyChangedEventHandlerが呼び出されないように、イベントフィールドはnullでなければならないようです。 RaiseProprtyChangedメソッドビルダーにメッセージボックスをいくつか追加しました。if(PropertyChanged!= null)はゼロまたはfalseを返すので、何も起こりません。 OpCodes.BrtrueをOpCodes.Brfalseに変更すると、「オブジェクト参照がオブジェクトのインスタンスに設定されていません」というメッセージが表示されます。 単純なものが欠けているように感じますが、見つけることができません。

            //implement IINotifyPropertyChanged interface
        tb.AddInterfaceImplementation(typeof(INotifyPropertyChanged));

        //property changed event handler
        FieldBuilder eventField = tb.DefineField("PropertyChanged", typeof(PropertyChangedEventHandler), FieldAttributes.Private);

        EventBuilder eb = tb.DefineEvent("PropertyChanged", EventAttributes.None, typeof(PropertyChangedEventHandler));

        MethodBuilder mbEV = tb.DefineMethod("remove_PropertyChanged", MethodAttributes.Public |
            MethodAttributes.SpecialName | MethodAttributes.NewSlot |
            MethodAttributes.HideBySig | MethodAttributes.Virtual |
            MethodAttributes.Final, null, new[] { typeof(PropertyChangedEventHandler) });

        MethodImplAttributes eventMethodFlags = MethodImplAttributes.Managed; //| MethodImplAttributes.Synchronized;
        mbEV.SetImplementationFlags(eventMethodFlags);
        il = mbEV.GetILGenerator();
        il.Emit(OpCodes.Ldarg_0);
        il.Emit(OpCodes.Ldarg_0);
        il.Emit(OpCodes.Ldfld, eventField);
        il.Emit(OpCodes.Ldarg_1);
        il.EmitCall(OpCodes.Call, typeof(Delegate).GetMethod("Remove", new[] { typeof(Delegate), typeof(Delegate) }), null);
        il.Emit(OpCodes.Castclass, typeof(PropertyChangedEventHandler));
        il.Emit(OpCodes.Stfld, eventField);
        il.Emit(OpCodes.Ret);
        MethodInfo miRemoveEvent = typeof(INotifyPropertyChanged).GetMethod("remove_PropertyChanged");
        tb.DefineMethodOverride(mbEV, miRemoveEvent);
        eb.SetRemoveOnMethod(mbEV);

        mbEV = tb.DefineMethod("add_PropertyChanged", MethodAttributes.Public |
            MethodAttributes.SpecialName | MethodAttributes.NewSlot |
            MethodAttributes.HideBySig | MethodAttributes.Virtual |
            MethodAttributes.Final, null, new[] { typeof(PropertyChangedEventHandler) });

        mbEV.SetImplementationFlags(eventMethodFlags);
        il = mbEV.GetILGenerator();
        il.Emit(OpCodes.Ldarg_0);
        il.Emit(OpCodes.Ldarg_0);
        il.Emit(OpCodes.Ldfld, eventField);
        il.Emit(OpCodes.Ldarg_1);
        il.EmitCall(OpCodes.Call, typeof(Delegate).GetMethod("Combine", new[] { typeof(Delegate), typeof(Delegate) }), null);
        il.Emit(OpCodes.Castclass, typeof(PropertyChangedEventHandler));
        il.Emit(OpCodes.Stfld, eventField);
        il.Emit(OpCodes.Ret);
        MethodInfo miAddEvent = typeof(INotifyPropertyChanged).GetMethod("add_PropertyChanged");
        tb.DefineMethodOverride(mbEV, miAddEvent);
        eb.SetAddOnMethod(mbEV);

        MethodInfo msgboxMethodInfo = typeof(System.Windows.Forms.MessageBox).GetMethod("Show", BindingFlags.Public | BindingFlags.Static, null, CallingConventions.Standard, new Type[] { typeof(String) }, null);

        MethodBuilder mbRaisePropertyChanged = tb.DefineMethod("RaisePropertyChanged", MethodAttributes.Virtual, null, new Type[] { typeof(string) });
        il = mbRaisePropertyChanged.GetILGenerator();
        System.Reflection.Emit.Label labelExit = il.DefineLabel();
        il.Emit(OpCodes.Ldarg_0);
        il.Emit(OpCodes.Ldfld, eventField);
        il.Emit(OpCodes.Ldnull);
        il.Emit(OpCodes.Ceq); //this is returning false
        il.Emit(OpCodes.Brtrue, labelExit);
        il.Emit(OpCodes.Nop); //I never get here
        il.Emit(OpCodes.Ldstr, "After If");
        il.EmitCall(OpCodes.Call, msgboxMethodInfo, null);
        il.Emit(OpCodes.Pop);
        il.Emit(OpCodes.Ldarg_0);
        il.Emit(OpCodes.Ldfld, eventField);
        il.Emit(OpCodes.Ldarg_0);
        il.Emit(OpCodes.Ldarg_1);
        il.Emit(OpCodes.Newobj, typeof(PropertyChangedEventArgs).GetConstructor(new[] { typeof(string) }));
        il.EmitCall(OpCodes.Callvirt, typeof(PropertyChangedEventHandler).GetMethod("Invoke"), null);
        il.Emit(OpCodes.Nop);
        il.Emit(OpCodes.Nop);
        il.MarkLabel(labelExit);
        il.Emit(OpCodes.Ret);


  • あなたはcastle dynamic proxyを使って別の解決策を試すことができます。dynamiccontrollers.codeplex.com。これはあなたの質問に対する直接的な解決策ではなく、単なる代替手段です。 - Elisha
  • これまでに取得したコードを表示してください。そして、「本物の」と「本当の」の違いは何ですか。これらのメソッドのバージョンとEmitで自分で生成したときに得たもの明らかに解決策はイベントに対して自動的に生成されるものと一致するようにあなたのバージョンを修正することを含みます。 - Kirk Woll
  • 上記のコードと追加情報を追加しました - Dan Schubel

1 답변


3

あなたがアセンブリのILを修正しようとしているならば、私は反省を避けます。あなたはアセンブリロック問題に出くわすかもしれません。

解決策としてはこれらのリンクを試してください。

カスタム織り

ポストシャープの使用

関連する質問

最近の質問