0

TL; DR

私は次のいずれかの方法を探しています:

  • ActionをとるをParamArray作成しますObject
  • Expression指定された数/タイプのジェネリックパラメーターに一致するアクションを作成するために使用します

詳細

非同期呼び出しをブロッキング呼び出しに変える関数を書いています。私の関数は、実行するタスク、タイムアウト値、およびStates結果として発生する可能性のある(イベントのようなもの)のコレクションを取ります。States複数のジェネリックパラメーターIState(of T)、IState(of T1、T2)などを定義しました。

Function MakeBlocking(task As Action,
                      resultingStates As IEnumberable(of IState),
                      Optional ByVal millisecondsTimeout As Integer = -1) 
                      As Boolean

  Dim are As New AutoResetEvent(False)
  Dim onFinish As New Action(Sub() are.Set())

  For Each state In resultingStates
    state.Subscribe(onFinish)
  Next

  task.Invoke()

  Dim result = are.WaitOne(millisecondsTimeout)

  For Each state In resultingStates
    state.Unsubscribe(onFinish)
  Next

  Return result
End Function

任意の数とタイプのパラメーターを持つIStateのコレクションを受け入れられるようにしたいと思います。IState(Of T)から継承しIState、からIState(Of T1, T2)継承するので、うまくいくIState(Of T)と思いますIEnumerable(Of IState)。問題は、Action私がそれらをサブスクライブしているのに、一致するパラメーターがないことです。

Public Interface IState(Of T1, T2)
  Inherits IState(Of T1)

  Shadows Function Subscribe(ByVal action As Action(Of T1, T2)) As IStateSubscription
  Shadows Function Unsubscribe(ByVal action As Action(Of T1, T2)) As Boolean

End Interface

ご覧のとおり、結果として、、、の状態が発生した場合は、それぞれに個別の状態が必要にIState(Of String, Boolean)なりIState(Of Integer)ます。私は本当にこのようなことをしたいと思っています:IState(Of String)Action

Dim onFinish As New Action(Sub(ParamArray stuff As Object())(Sub() are.Set())

しかし、それを行うための検証構文が見つからないようです(可能であれば)。他の唯一のオプションは、Expression.Lambdaを使用してサブスクライブできるメソッドを動的に作成することのようですが、これまで式ツリーの経験はあまりありませんでした。アクションExpressionからを作成する方法はありますか?OnFinish

州を扱っている図書館は私の管理外であることに注意する必要があります。基になるコードは、パラメーターの数と割り当て可能性(つまり、IsAssignableFrom)が一致することを確認します。したがって、すべてをとして渡してもIState、基になる型が実際に何であるかを調べて、サブスクライブできないことを通知Actionします。そのState

4

1 に答える 1

0

これが私が思いついたものです...

代表者と

回避策を使用しDelegateてVB.Netでを作成することができます。しかし、それがうまくいったかどうかはわかりません。デリゲートを動的に作成するために使用することもできます。ParamArrayExpression

Dim are As New AutoResetEvent(False)

Dim setMethod = are.GetType.GetMethod("Set")
Dim callSet = Expression.Call(Expression.Constant(are), setMethod)

For Each state In resultingStates
  Dim args = state.GetType.GetGenericArguments()
  Dim params = Enumerable.Range(1, args.Count).Select(
                 Function(x) Expression.Parameter(args(x - 1), "var" & x))
  Dim onFinish = Expression.Lambda(callSet, params.ToArray).Compile()

  state.Subscribe(onFinish) 'Doesn't compile since OnFinish isn't an Action
Next

ただし、が必要なため、これらのオプションはいずれも機能しませんActionから作成ActionDelegateできるように見えますが、一般的なタイプを知っている必要があるActionので、実行時まで利用できないものです。私の場合は、静的にタイプを知らなければキャストできないと思います。 )。

私の解決策

私は問題を少し分解することになった。以前は、次のように呼んでいました。

Public Function GetThing() As Boolean 'Returns success vs timeout
  Return MakeBlocking(Sub() SendAsyncThingRequest(), 
                      {ResultingState1, ResultingState2}, 
                      timeOutVal)
End Sub

代わりに私はそれを分解したので、発信者はもう少し責任があります:

Public Function GetThing() As Boolean
  Dim are As New AutoResetEvent(False)

  WaitFor(ResultingState1, are)
  WaitFor(ResultingState2, are)

  SendAsyncThingRequest()

  Return are.WaitOne(timeoutVal)
End Function

そして、結果の状態を「WaitFor」し、AutoResetEventいつ発生するかを設定する汎用メソッドがあります。

Protected Sub WaitFor(Of T)(ByVal waitUpon As IState(Of T), 
                            ByVal are As AutoResetEvent)

  Dim action As New Action(Of T)(
  Sub(x)
    are.Set()
    waitUpon.Unsubscribe(action)
  End Sub)

  waitUpon.Subscribe(action)
End Sub

これは、私の特定のシナリオにとって最も単純でクリーンなソリューションになりました。

于 2012-07-25T16:32:30.887 に答える