2
Private Sub LoadData(Of T)(ByVal query As ObjectQuery(Of T), 
    ByRef result As IEnumerable(Of T))
  If Connection.State = ConnectionState.Open Then
    result = query.ToArray
  Else
    AddHandler Connection.StateChange,
      Sub(sender As Object, e As StateChangeEventArgs)
        LoadData(query, result)
      End Sub
  End If
End Sub

上記のコードでは、接続が利用できないときに LoadData 関数を再帰しようとしています。利用可能になったときにロードを延期したいと考えています。

問題は、ラムダ式で param を使用できないためByRef上記のコードによってコンパイラ エラーが発生することです。

これを正しい方法で行う方法はありますか?

4

2 に答える 2

3

ByRefラムダが実行されると存在しなくなったスタック上の場所を指している可能性があるため、ラムダでパラメーターを使用することはできません。より「永続的な」保管場所を使用するだけです。IEnumerable(Of T)結果を割り当てるために設定できるプロパティを持つオブジェクトを渡すことができます。

Action<IEnumerable<T>>おそらくより良いオプションは、結果を受け入れ、結果に対して呼び出し元が必要とするアクションを実行するデリゲート ( ) を渡すことです。C# での例を次に示します。

void LoadData<T>(ObjectQuery<T> query, Action<IEnumerable<T>> action)
{
    if (Connection.State == ConnectionState.Open)
        action(query.ToArray());
    else
    {
        // create a lambda to handle the next state change
        StateChangeEventHandler lambda = null;
        lambda = (sender, e) =>
        {
            // only perform our action on transition to Open state
            if (Connection.State == ConnectionState.Open)
            {
                // unsubscribe when we're done
                Connection.StateChange -= lambda;
                action(query.ToArray());
            }
        }
        // subscribe to connection state changes
        Connection.StateChange += lambda;
    }
}

そして、次のように呼び出しますLoadData

LoadData(query, results => listBox.DataSource = results);

私の実装のニュアンスに注意してください。たとえば、イベント ハンドラー内でそれ自体を呼び出すことはありません。これは、ハンドラーが 以外の状態で呼び出された場合にイベントを再サブスクライブするためですOpen。また、接続が開くと、イベントへの登録も解除されます。これが VB にどのように変換されるかはわかりませんが、C# では 3 ステップのプロセスです。最初に、ラムダを保持する変数を宣言し、その値を null に設定する必要があります。次に、ラムダを作成します。ラムダは、自分自身を参照してサブスクライブを解除できます。最後に、ラムダを使用してイベントをサブスクライブできます。

于 2011-01-26T03:41:43.817 に答える
0

LoadData()変数が呼び出しによって設定されているかどうかを呼び出しスレッドが認識できないという問題があります。

この場合、次のようにする必要があります。

  • 読み込みが完了するまで実行をブロックする
  • ロードが完了したときにイベントを発生させる
  • ローダーに公開フィールドを設定して、読み込みステータスを示します

1 つの (考えられる) 妥協案は、IEnumerable の代わりにカスタム オブジェクトを返すことです。

カスタム オブジェクトはすぐにデータの読み込みを試行し、成功するまで再試行を続けることができます。ロードが発生する前にカスタム オブジェクトの結果セットが読み取られた場合は、ロードが完了するまでスレッドをブロックし、それ以外の場合は結果セットを返します。

このシナリオでは、Load が発生してからデータが使用されるまでの間に遅延がある場合にメリットが得られます。プログラムは、データが必要になるまで続行できます。これが役立つかどうかは、使用目的に完全に依存します。

実行のブロックに関する詳細情報: 接続がバックアップされたことをどのように認識するかによって少し異なりますが、次のようなものです。

Public Sub LoadData(Of T)(ByVal query As ObjectQuery(Of T), ByRef result As IEnumerable(Of T))
  While Not Connection.State = ConnectionState.Open
    Threading.Thread.Sleep(100) 'Pick a decent value for this delay based on how likely it is the connection will be available quickly
  End While
  result = 'Use the connection to get your data
End Sub

関数ではなく ByRef パラメータを持つサブとしてこれを行う理由はありますか? あなたは1つのオブジェクトを「返す」だけなので、その利点はよくわかりません。機能的に大きな違いがあるわけではありませんが、読みやすくなります...

于 2011-01-26T03:43:12.753 に答える