2017-04-04 18 views
0

これで、私はしばらくの間、この問題を解決しました。実行時に生成された不明な型のイベントハンドラ

状況:

Iが変化することができるactivator.CreateInstance(X)

X型を用いて、タイプXのオブジェクトをインスタンス化するが、常に同じプロパティとメソッドを有します。 問題は、タイプxはReadCompleted(これはデリゲート)のイベントReadCompletedを持ち、タイプyは同じデリゲートで同じイベントを持ちますが、ReadCompleted1、z => ReadCompleted2などのタイプです。

ソリューション: は、私は、次のコードを使用して、実行時にデリゲートを割り当てます。

Dim Client As Object = ServiceProvider.GetService(TypeDict(Entity)) 
    Dim TaskCompletionSource As New TaskCompletionSource(Of Entity)() 

    Dim addMethod As MethodInfo = Client.GetType().GetMethod("add_ReadCompleted") 
    Dim removeMethod As MethodInfo = Client.GetType().GetMethod("remove_ReadCompleted") 

    Dim self As Object = Nothing 
    Dim getSelf As Func(Of Object) = Function() self 

    Dim eventArgType As Type = Client.GetType().GetEvent("ReadCompleted").EventHandlerType.GetMethod("Invoke").GetParameters()(1).ParameterType 

    Dim e As ParameterExpression = Expression.Variable(eventArgType) 

    Dim ExpBlock As BlockExpression = Expression.Block({Expression.Parameter(GetType(Object)), e}, 
     Expression.Call(
      Nothing, 
      Me.GetType().GetMethod("ProcessTask"), 
      Expression.Convert(e, eventArgType), 
      Expression.Constant(TaskCompletionSource)), 
    Expression.Call(
     Expression.Constant(Client), 
     removeMethod, 
     Expression.Convert(
      Expression.Invoke(
       Expression.Constant(getSelf)), 
      addMethod.GetParameters()(0).ParameterType) 
     ) 
     ) 

    Dim lambda As LambdaExpression = Expression.Lambda(
     addMethod.GetParameters()(0).ParameterType, 
     ExpBlock, 
     Expression.Parameter(GetType(Object)), 
     Expression.Parameter(eventArgType)) 
    Dim dlg As [Delegate] = lambda.Compile() 
    self = dlg 

    addMethod.Invoke(Client, {dlg}) 

    Client.ReadAsync(PrimaryKey) 

今私のLINQの知識と、それはExpressionクラスが限られていると私は、MSDNのドキュメントを検索するには、私のベストを尽くしたが、私はそれを理解できないのですout:

メソッドProcessTaskが正しく呼び出されます。私のパラメータeは常にNothingなので、NullReferenceExceptionが発生します。 方法:

Public Shared Sub ProcessTask(ByVal e, ByRef tcs) 
    'Console.WriteLine(e.GetType()) 
    If e.Error IsNot Nothing Then 
     tcs.TrySetException(e.Error) 
    ElseIf e.Cancelled Then 
     tcs.TrySetCanceled() 
    Else 
     tcs.TrySetResult(e.Result) 
    End If 
End Sub 

は、私は私はこれが私のメソッドを呼び出すための正しい方法ですが、明らかにそれはないそれを見る方法によると、理由はわかりません。誰かがこれに対して正しい方向に向けることができますか? 私はまったく目立たず、何か非常に明白なものがありませんでした....

ありがとうございます!

EDIT:オブジェクトパラメータとして

Dim s As ParameterExpression = Expression.Variable(GetType(Object), "Sender") 
    Dim ExpBlock As BlockExpression = Expression.Block({s, e}, 
               Expression.Call(
                Nothing, 
                GetType(Console).GetMethod("WriteLine", New Type() {GetType(String)}), 
                Expression.Call(s, GetType(Object).GetMethod("ToString"))), 
               Expression.Call(
      Expression.Constant(Client), 
      removeMethod, 
      Expression.Convert(
       Expression.Invoke(
        Expression.Constant(getSelf)), 
       addMethod.GetParameters()(0).ParameterType) 
      )) 

送信者も何もありませんので、私: 私はいくつかのより多くのデバッグを実行しようとしました答えを待っている間は(このシナリオでは地獄である)私がしなければことを見ました私の議論のどれも通過していないと感じている...

これは、問題についてより多くの光を出すのに役立ちます。 )((エンティティの)新TaskCompletionSourceなどのオブジェクト= ServiceProvider.GetService(TypeDict(エンティティ)) 点心TaskCompletionSourceとして

薄暗いクライアント:

+0

もし私がそれを見逃しているのかどうかは分かりませんが、実際には明らかですが、どこで 'ProcessTask'を呼び出していますか? – David

+0

こんにちは@David、見ていただきありがとうございます。 ProcessTaskの呼び出しは、式 'Expression.Call( Nothing、 Me.GetType()。GetMethod(" ProcessTask ")、 の式の内部にあります。 少なくとも、それは私がそれがしていると思う、または少なくともそれが何をすると思われるかです... この式は、実際にはReadCompletedイベントのハンドラです。クライアント。 –

+0

また、私はProcessTaskメソッドがReadCompletedEventでトリガされることを知っています、それはちょうど動的なeventargsを渡していないか、それがnullのような結果になるか変換しません... –

答えて

0

私はそれを考え出したが、私は式の全パラメータのことを誤解判明します

Dim addMethod As MethodInfo = Client.GetType().GetMethod("add_ReadCompleted") 
Dim removeMethod As MethodInfo = Client.GetType().GetMethod("remove_ReadCompleted") 

Dim self As Object = Nothing 
Dim getSelf As Func(Of Object) = Function() self 

Dim eventArgType As Type = Client.GetType().GetEvent("ReadCompleted").EventHandlerType.GetMethod("Invoke").GetParameters()(1).ParameterType 

Dim s As ParameterExpression = Expression.Parameter(GetType(Object), "Sender") 
Dim e As ParameterExpression = Expression.Variable(eventArgType, "EventArgs") 

Dim ExpBlock As BlockExpression = Expression.Block(\*{Expression.Parameter('GetType(Object)), e},*\ <--- this has to go 
    Expression.Call(
     Nothing, 
     Me.GetType().GetMethod("ProcessTask"), 
     Expression.Convert(e, eventArgType), 
     Expression.Constant(TaskCompletionSource)), 
Expression.Call(
    Expression.Constant(Client), 
    removeMethod, 
    Expression.Convert(
     Expression.Invoke(
      Expression.Constant(getSelf)), 
     addMethod.GetParameters()(0).ParameterType) 
    ) 
    ) 

Dim lambda As LambdaExpression = Expression.Lambda(
    addMethod.GetParameters()(0).ParameterType, 
    ExpBlock, 
    s, 
    e) 
    \*Expression.Parameter(GetType(Object)), 
    Expression.Parameter(eventArgType))*\ <-- this has to change 
Dim dlg As [Delegate] = lambda.Compile() 
self = dlg 

addMethod.Invoke(Client, {dlg}) 

Client.ReadAsync(PrimaryKey) 

私はそれを見るようにパラメータが表現自体に定義する必要はありませんが、それらが作成さsould、および参照は、あなたが表現をコンパイルしたラムダでそれらを使用するために保管しなければなりません。

今後、この回答に誰かが役に立つと思っています。この回答をお寄せいただきありがとうございます。

関連する問題