2012-03-22 20 views
2

我有一個這樣的接口:是否有可能隱藏回調機制在一個單一的方法?

interface IAuthentication 
{ 
    void AuthenticateAsync(string user, string pwhash); 
    event EventHandler<AuthenticationResult> AuthenticationDone; 
} 

這是通過在完成時引發事件。現在,我想它完成後包裹返回認證結果單,阻斷方法在這裏面的機制:

AuthenticationResult Authenticate(string user, string pwhash) 
{ 
    var auth = GetIAuthenticator(); 
    // ... do something 
    return <the authentication result from the even argument>; 
} 

這可能不知?

+0

您在使用.NET 4.0?如果是,那麼任務並行庫將幫助你。 – ken2k 2012-03-22 13:34:27

+0

是的,我正在使用.NET 4.0。 – 2012-03-22 13:38:26

回答

3

隨着等待句柄,你並不需要檢查一些標誌,塊線程和設定的超時:

private AuthenticationResult Authenticate(string user, string pwhash) 
{    
    IAuthentication auth = GetIAuthenticator(); 
    AuthenticationResult result = null; 
    AutoResetEvent waitHangle = new AutoResetEvent(false); 

    auth.AuthenticationDone += (o, e) => 
     { 
      result = e; 
      waitHangle.Set(); 
     }; 

    auth.AuthenticateAsync(user, pwhash); 
    waitHangle.WaitOne(); // or waitHangle.WaitOne(interval); 
    return result; 
} 
+1

這將等待多久破碎的網絡連接/等? – sll 2012-03-22 14:55:45

+0

您可以使用重載的WaitOne方法,最大間隔時間等待。 – 2012-03-22 14:58:10

+1

我認爲它需要間隔來阻止。不過,這確實是一個非常優雅的解決方案。 – 2012-03-22 15:00:22

2
private AuthenticationResult Authenticate(string user, string pwhash) 
{ 
    bool isDone = false; 
    AuthenticationResult results = null 
    var auth = GetIAuthenticator(); 
    auth.AuthenticationDone += (o, e) => 
    { 
     isDone = true; 
     results = e; 
    }; 

    auth.AuthenticateAsync(user, pwhash); 

    long maxWaitTimeSeconds = 10; 
    long thresholdMilliseconds = 100; 
    int countToWait = maxWaitTimeSeconds * 1000/thresholdMilliseconds; 
    while (!isDone || countToWait-- > 0) 
    { 
     Thread.Sleep(thresholdMilliseconds); 
    } 

    if (countToWait == 0 && !isDone) 
    { 
     // TODO: timeout handling 
    } 

    return results;  
} 

PS: 如果事件參數永遠不能爲null - 你可以擺脫isDone可變的,只是使用result != null爲「完成認證」指標

+0

lambda是否參考了isDone變量? – 2012-03-22 13:44:17

+0

如果您有另一個線程並使用等待/通知方法,您將具有更好的響應能力並降低浪費的輪詢/旋轉。 – Servy 2012-03-22 13:45:16

+0

@TamásSzelei它並沒有真正傳遞它;它只是在你看到它在這裏使用的任何地方訪問相同的變量。 – Servy 2012-03-22 13:46:03

2

當你使用.NET 4.0,你可以利用任務並行庫。

這裏是一個非常基本的程序,說明如何使用TaskCompletionSource

public class Test 
{ 
    public void Go() 
    { 
     ThreadPool.QueueUserWorkItem((z) => this.Imp()); 
    } 

    private void Imp() 
    { 
     Console.WriteLine("Asynchronous operation in progress (1/2)..."); 
     Thread.Sleep(2000); 
     Console.WriteLine("Asynchronous operation in progress (2/2)..."); 

     if (this.Done != null) 
     { 
      this.Done(this, EventArgs.Empty); 
     } 
    } 

    public event EventHandler Done; 
} 

internal class Program 
{ 
    private static void Main(string[] args) 
    { 
     Test test = new Test(); 

     TaskCompletionSource<object> tcs = new TaskCompletionSource<object>(null); 

     Console.WriteLine("Starting asynchronous operation"); 

     Task.Factory.StartNew(() => 
     { 
      test.Done += (sender, e) => tcs.SetResult(null); 
      test.Go(); 
     }); 

     // Blocking until completion of the async operation 
     var tmp = tcs.Task.Result; 

     Console.WriteLine("Asynchronous operation completed"); 

     Console.ReadKey(); 
    } 
} 

結果是:

Starting asynchronous operation 
Asynchronous operation in progress (1/2)... 
Asynchronous operation in progress (2/2)... 
Asynchronous operation completed 

正如你所看到的,執行流程被阻塞,直到異步操作終止。

+0

爲什麼在同步請求的情況下需要單獨的線程? – sll 2012-03-22 14:04:20

+0

@sll沒有創建線程,而是開始了一個任務,這是不一樣的。使用TPL是利用TaskCompletionSource類的例子。 – ken2k 2012-03-22 14:10:43

+0

AFAIK TPL可以或不可以爲異步操作創建一個線程(在池中),我相信你無法控制這個,我錯了嗎?順便說一句,你的示例輸出說其他 - 「主線程..另一個線程」,它是什麼意思呢? – sll 2012-03-22 14:13:56

相關問題