1

WCF非同期メソッドを使用しています。

コールバック関数の値を返そうとすると問題が発生します。

可能な解決方法は何ですか?(.net 4.0を使用しますが、4.5は使用しません

    public static Object LoadInfo()
    {
        var service = new SomeWcfService();
        service.BeginGetInfo(CallbackMethod, service);

        // HOW TO GET INFROMATION FROM CALLBACK??
        return INFORMATION;
    }

    private static void CallbackMethod(IAsyncResult ar)
    {
        // HOW TO PASS INFROMATION TO LoadInfo??
        var INFORMATION = (ar.AsyncState as SomeWcfService).EndGetInfo(ar);
    }

注:すべての作業は非同期で行う必要があります。

ありがとう。

4

2 に答える 2

1

非同期パターンと戦うよりも、非同期パターンを使用するように設計することをお勧めします。

ただし、非同期メソッドに同期的にアクセスする必要がある場合は、セマフォを使用して、非同期メソッドが戻るまで呼び出しスレッドをブロックできます。

public static Object LoadInfo()
{
    // this is our semaphore
    var blocker = new AutoResetEvent();
    object result = null;

    var service = new SomeWcfService();
    // use a lambda instead of a method as the callback.
    // this will result in a closure where we can access the result and blocker variables
    service.BeginGetInfo(x => 
    {
        // We are on a different thread within this lambda
        result = (x.AsyncState as SomeWcfService).EndGetInfo(ar);
        // release anybody calling blocker.WaitOne
        blocker.Set(); 
    }, service);

    // we are still on the original thread here, and
    // BeginGetInfo has possibly not yet executed, so we must wait until Set is called
    blocker.WaitOne(Timeout.Infinite); 
    return result;
}

これが適切な設計の選択になることはめったにありません。非同期パターンはレスポンシブ UI に適しています。このようなことをした方が良い

public void LoadInfo()
{
    // Makes the UI show a loading indicator, blocking all actions except for CANCEL
    LoadingInfo = true;

    var service = new SomeWcfService();
    service.BeginGetInfo(CallbackMethod, service);
}

private void CallbackMethod(IAsyncResult ar)
{
    // the UI is now released from loading 
    LoadingInfo = false;
    // the UI is triggered to show our data
    ViewModel.Data = (ar.AsyncState as SomeWcfService).EndGetInfo(ar);
}
于 2012-08-30T15:47:42.573 に答える
1

特にコールバックを使用して、最初に非同期を理解するのは難しいです。あなたの例では、間違っていますが、自然な仮定をしています...

public static Object LoadInfo() 
{ 
    var service = new SomeWcfService(); 
    service.BeginGetInfo(CallbackMethod, service); 

    // HOW TO GET INFROMATION FROM CALLBACK?? 
    // ERROR: You assume you have more work to do in this method,
    // or that this is the place to return your results.
    return INFORMATION; 
} 

以下に示す方法は、結果が返された後に作業が行われる場所です。

private static void CallbackMethod(IAsyncResult ar) 
{ 
    // HOW TO PASS INFROMATION TO LoadInfo?? 
    // OOPS! No need to pass pack to LoadInfo - it's done...
    var INFORMATION = (ar.AsyncState as SomeWcfService).EndGetInfo(ar); 
}

代わりに、このようなものが必要になります

public static void LoadInfo()        
{        
    var service = new SomeWcfService();        
    // begin an asynchronous service call
    // and handle the results in another method, "CallbackMethod"
    service.BeginGetInfo(CallbackMethod, service);  
    // You can do other, non-service related,
    // things here while the service call executes 
}   

次に、他のメソッドがすべての結果を処理します。

private static void CallbackMethod(IAsyncResult ar)            
{            
    var results = (ar.AsyncState as SomeWcfService).EndGetInfo(ar);  
    // Do whetever you need with results here
}    

Will が彼の優れた回答で指摘したように (+1、彼が必要としているかのように笑!)、別のコールバック メソッドを使用する代わりに、次のようなラムダ式で匿名メソッドを使用できます。

public static void LoadInfo()        
{        
    var service = new SomeWcfService();        
    // begin an asynchronous service call
    // and handle the results in this anonymous method
    service.BeginGetInfo(x =>
    {
        // B. This code block will be called when the service returns with results
        var results = (ar.AsyncState as SomeWcfService).EndGetInfo(ar);  
        // Do whetever you need with results here
    }, service);  

    // A. You can do other things here while the service call executes
    // but debugging this gets more complicated because things will likely
    // occur at A before they occur at B
}

したがって、非同期の全体的な考え方は次のとおりです。

  • あなたのプログラムは、サービス呼び出しをセットアップして開始し、待機することなく、必要なことを続けます。ヒント: これは、ローディング アニメーションを開始したり、一部のコントロールを無効にしたりするのに自然な場所です。
  • 非同期呼び出しを行ったとき、パラメーターの 1 つとして、呼び出しが完了したときに実行するメソッドを指定しました。
  • サービスが結果を返すと、指定したメソッドが実行され、結果に対する作業が行われます。ヒント: このメソッドでは、ロード アニメーションを終了したり、コントロールを再度有効にしたり、結果を ViewModel にプラグインしたりできます。
于 2012-08-30T17:45:53.793 に答える