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結合成爲控制檯運行問題?
有你的STA線程('Application.Run')沒有消息循環,這是強制性的'Invoke'支持。 –
哦,這似乎是絕對合理的,顯然...我明天會檢查它並提供反饋。非常感謝 –
@ stev-e:在附註中,我總是不鼓勵使用「InvokeRequired」。 「安全調用」方法是一種反模式。代碼應該總是知道它在哪裏運行,並且線程跳轉應該是明確的。 –