3 回答

TA貢獻1799條經(jīng)驗 獲得超9個贊
DoEvents()很危險。但我敢打賭,你每天都會做很多危險的事情。就在昨天,我引爆了一些爆炸裝置(未來的讀者:請注意相對于某個美國假期的原始發(fā)布日期)。小心,我們有時可以解釋危險。當(dāng)然,這意味著了解并了解危險是什么:
重新進入的問題。這里實際上有兩個危險:
這里的部分問題與調(diào)用堆棧有關(guān)。如果在循環(huán)中調(diào)用.DoEvents(),該循環(huán)本身處理使用DoEvents()的消息,依此類推,則會得到一個非常深的調(diào)用堆棧。很容易過度使用DoEvents()并意外填滿調(diào)用堆棧,從而導(dǎo)致StackOverflow異常。如果你只在一兩個地方使用.DoEvents(),你可能還可以。如果它是您長時間運行過程中的第一個工具,那么您可以輕松地在這里遇到麻煩。即使在錯誤的地方使用一次也可以使用戶強制執(zhí)行stackoverflow異常(有時只需按住enter鍵),這可能是一個安全問題。
有時可以在調(diào)用堆棧上找到相同的方法兩次。如果你沒有記住這個方法(提示:你可能沒有),那么可能會發(fā)生不好的事情。如果傳入方法的所有內(nèi)容都是值類型,并且不依賴于方法之外的東西,那么您可能沒問題。但除此之外,您需要仔細考慮如果在調(diào)用.DoEvents()之前將控制權(quán)返回給您之前再次運行整個方法會發(fā)生什么。您的方法之外的哪些參數(shù)或資源可能會被修改為您沒想到的?您的方法是否更改了任何對象,其中堆棧上的兩個實例可能都在同一個對象上?
性能問題。DoEvents()可以給出多線程的錯覺,但它不是真正的多線程。這至少有三個真正的危險:
當(dāng)您調(diào)用DoEvents()時,您將現(xiàn)有線程的控制權(quán)交還給消息泵。消息泵可能反過來控制其他東西,而其他東西可能需要一段時間。結(jié)果是你的原始操作可能需要更長的時間來完成,而不是它本身的線程永遠不會產(chǎn)生控制,絕對比它需要的更長。
重復(fù)工作。因為有可能發(fā)現(xiàn)自己運行兩次相同的方法,并且我們已經(jīng)知道這個方法很昂貴/長時間運行(或者你首先不需要DoEvents()),即使你考慮了所提到的所有外部依賴性因此沒有不良的副作用,你可能仍然會重復(fù)很多工作。
另一個問題是第一個問題的極端版本:潛在的僵局。如果你的程序中的其他內(nèi)容取決于你的進程完成,并且會阻塞直到它完成,并且那個東西被來自DoEvents()的消息泵調(diào)用,你的應(yīng)用程序?qū)⒈豢ㄗ〔⒆兊脽o法響應(yīng)。這可能聽起來很牽強,但在實踐中,意外地做起來非常容易,并且以后很難找到并調(diào)試崩潰。這是您在自己的計算機上可能遇到的一些掛起應(yīng)用程序情況的根源。
可用性問題。這些副作用是由于不能正確解釋其他危險造成的。這里沒有什么新東西,只要你適當(dāng)?shù)乜雌渌胤健?/p>
如果你能確定你已經(jīng)解決了所有這些問題,那就繼續(xù)吧。但實際上,如果DoEvents()是您首先要解決的UI響應(yīng)/更新問題,那么您可能無法正確解決所有這些問題。如果它不是你看的第一個地方,還有足夠的其他選項,我會質(zhì)疑你是如何考慮DoEvents()的。
現(xiàn)實情況是,大多數(shù)情況下,至少在.Net世界中,BackgroundWorker組件幾乎一樣容易,至少一次完成一次或兩次,它將以安全的方式完成工作。最近,異步/等待模式或使用a Task
可以更加有效和安全。

TA貢獻1836條經(jīng)驗 獲得超13個贊
我可能錯了,但在我看來DoDragDrop
并且TrackPopupMenu
是相當(dāng)特殊的情況,因為它們接管了UI,因此沒有重入問題(我認為這是人們DoEvents
稱之為“邪惡”的主要原因)。
就個人而言,我認為將某個功能視為“邪惡”并不合適 - 而是解釋陷阱,以便人們可以自行決定。在DoEvents
極少數(shù)情況下,使用它仍然是合理的,例如在顯示模態(tài)進度對話框時,用戶無法與UI的其余部分進行交互,因此不會出現(xiàn)重入問題。
當(dāng)然,如果用“邪惡”來表示“你不應(yīng)該在沒有完全理解陷阱的情況下使用的東西”,那么我同意這DoEvents
是邪惡的。

TA貢獻1765條經(jīng)驗 獲得超5個贊
回到16位Windows時代,當(dāng)每個任務(wù)共享一個線程時,保持程序在緊密循環(huán)中響應(yīng)的唯一方法是DoEvents。這種非模態(tài)用法不支持線程。這是一個典型的例子:
' Process image
For y = 1 To height
For x = 1 to width
ProcessPixel x, y
End For
DoEvents ' <-- DON'T DO THIS -- just put the whole loop in another thread
End For
對于模態(tài)事物(如跟蹤彈出窗口),它可能仍然可以。
- 3 回答
- 0 關(guān)注
- 779 瀏覽
添加回答
舉報