5

C #/ .Net 4.0을 사용하면 dataRow가 Reflection.Emit을 통해 런타임에 정의되는 BindingList에 데이터를 저장합니다. 수신 데이터의 구조는 다양하며 외부 소스에 의해 정의됩니다. 리플렉션과 일리노이의 세계에 첫 발을 디디 며 조금 어려움을 겪은 후에 필자는 dataRow를 값으로 채우고 BindingList를 채우고 결과를 그리드에 표시 할 수있었습니다. 이제 데이터가 변경되면 INotifyPropertyChanged 인터페이스와 PropertyChangedEventHandler를 구현하려고합니다. 사용지침으로 실행되는 코드가 있지만 RaisePropertyChanged 이벤트가 실행 중이거나 아무것도 수행하지 않는 것으로 나타나지 않습니다. 동적 버전을 ildasm.exe를 통해 일반 / 정적 버전과 비교할 때 remove_PropertyChanged 및 add_PropertyChanged 메소드의 주요 차이점을 확인할 수 있습니다. 누구나 리플렉션을 통해 INotifyPropertyChanged 인터페이스를 구현하는 몇 가지 팁이나 예제를 제공 할 수 있습니까?

추가 검토 후 PropertyChangedEventHandler가 호출되지 않도록 이벤트 필드가 null이어야합니다. RaiseProprtyChanged 메소드 빌더에 일부 메시지 상자를 추가하고if (PropertyChanged! = null)0 / 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);


  • 성 동적 프록시를 사용하는 대체 솔루션을 시도해 볼 수 있습니다.dynamiccontrollers.codeplex.com. 이것은 귀하의 질문에 대한 직접적인 해결책이 아니라 다른 대안입니다. - Elisha
  • 지금까지 얻은 코드를 알려주세요. " 실제 "와 " 버전의 메소드와 Emit에서 직접 생성 할 때 얻은 메소드가 있습니까? 분명히 해결책은 자동으로 생성되는 이벤트와 일치하도록 버전을 수정하는 것입니다. - Kirk Woll
  • 위 코드 및 추가 정보를 추가했습니다. - Dan Schubel

1 답변


3

조립품의 일리노이를 수정하려고하는 경우 반사가 명확하지 않습니다. 어셈블리 잠금 문제가 발생할 수 있습니다.

해결책은이 링크를 사용하십시오.

맞춤 짜기

포스트 샤프 사용하기

관련된 질문

최근 질문