2017-04-04 15 views
0

好的,所以我一直堅持這一段時間,結合了來自這裏的各種問題解決方案。未知類型的運行時生成的EventHandler

情況:

我通過使用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和知識,這是表達類是有限的,我盡我所能去研究的MSDN文檔,但我想不出它out:

ProcessTask被調用的方法正確,爲此我wo足夠長的時間,但我的參數e總是沒有,導致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 

我不知道爲什麼,根據我怎麼看它這個是叫我的方法正確的方法,但顯然事實並非如此。有人能爲我指出正確的方向嗎? 可能是我只是普通的盲人,失去了非常明顯的東西....

在此先感謝!

編輯: 雖然等待一個答案,我試圖做一些更多的調試(這是地獄在這種情況下)看到,如果我這樣做:

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) 
      )) 

發送者爲對象的參數也不算什麼,所以我我的感覺是我的論點都沒有通過...

希望這有助於闡明這件事。

+0

不知道如果我只是想念它,它實際上很明顯,但是,你在哪裏調用'ProcessTask'? – David

+0

嗨@David,謝謝你看看。 對ProcessTask的調用在以下表達式內: 'Expression.Call( Nothing, Me.GetType()。GetMethod(「ProcessTask」), 表達式。轉換(e,eventArgType), Expression.Constant(TaskCompletionSource))' 至少這就是我認爲它的作用,或者至少它應該做什麼...... 該表達式實際上是ReadCompleted事件的處理程序客戶端。 –

+0

此外,我知道在ReadCompletedEvent上觸發ProcessTask方法,它只是以某種方式不傳遞動態事件列表,或者沒有將其轉換爲正確的結果爲null或類似的東西......對於後者我無能爲力...... –

回答

0

我想通了,原來我誤解表達的完整參數的事情:

昏暗的客戶爲對象= ServiceProvider.GetService(TypeDict(實體)) 昏暗TaskCompletionSource作爲新TaskCompletionSource(實體)()

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) 

所以當我看到它的參數沒有在表達式本身來定義,但他們被前人的精力創建,並參考應保持在其中您編譯表達式的拉姆達使用它們。

希望有人在未來有一些使用這個答案,並感謝所有的看看這個。