2017-01-31 40 views
0

我只是玩弄了一下這個整潔的代碼CodeprojectEndInvoke會()不返回(循環死鎖?)

有用於控制安全調用方法:

public static TResult SafeInvoke<T, TResult>(this T isi, Func<T, TResult> call) where T : ISynchronizeInvoke 
{ 
    if (isi.InvokeRequired) { 
     IAsyncResult result = isi.BeginInvoke(call, new object[] { isi }); 
     object endResult = isi.EndInvoke(result); return (TResult)endResult; 
    } 
    else 
     return call(isi); 
} 

方案1:帶有WebBrowser控件的Windows窗體應用程序。此調用返回它應該(返回的結果是,此刻也不管,只是爲了測試左右)內容:從創建安全調用這個片段的傢伙

private void button1_Click(object sender, EventArgs e) 
{ 
    Thread thread = new Thread(new ThreadStart(StartStuff)); 
    thread.Start(); 
} 

private void StartStuff() 
{   
    var document = webBrowser1.SafeInvoke(o => o.Document);  
} 

到目前爲止好,不錯。

場景2:接下來我想運行一些單元測試來處理一些基於WebBrowser的東西。這個小試驗應證明這一點:

[Test, Category("Thread Safety")] 
public void TestIfThreadRaisesException() 
{ 
    /* create STA thread where the browser will live and die in */ 
    Thread thread = new Thread(RunSTAContent); 
    thread.SetApartmentState(ApartmentState.STA); 
    thread.Start(); 
    thread.Join(); 
} 

private static void RunSTAContent() 
{ /* simulate cross thread access to control */ 
    var stdBrowser = new System.Windows.Forms.WebBrowser(); 
    Task.Run(async() => await RunUnProblematicContent(stdBrowser)).Wait(); 
} 

private static async Task RunUnProblematicContent(System.Windows.Forms.WebBrowser browser) 
{ 
    await Task.Delay(1000); 
    var doc = browser.SafeInvoke(o => o.Document); 
    //... 
} 

這樣一來,我可以SafeInvoke無限通話,更確切地說它在這裏結束:

object endResult = isi.EndInvoke(result); 

你有一個提示,爲何調用永遠不會結束?更多是因爲我自制的STA線程?它可能與NUnit結合成爲控制檯運行問題?

+3

有你的STA線程('Application.Run')沒有消息循環,這是強制性的'Invoke'支持。 –

+0

哦,這似乎是絕對合理的,顯然...我明天會檢查它並提供反饋。非常感謝 –

+2

@ stev-e:在附註中,我總是不鼓勵使用「InvokeRequired」。 「安全調用」方法是一種反模式。代碼應該總是知道它在哪裏運行,並且線程跳轉應該是明確的。 –

回答

0

如Ivans評論所述,消息循環丟失。 我遇到了這個類,我可以用於此用途:)

MessageLoopApartment