2011-09-01 53 views
1

在最初的代碼是這樣的:的IEnumerable VS IList的和奇怪的CrossThreadMessagingException調試

var processes = Process.GetProcesses().Where(p => p.MainWindowTitle.ToUpperInvariant().Contains("FOO")); 

在調試過程中,如果我嘗試在即時窗口窗格中調用Count()processes或檢查在當地人的「結果視圖」窗格中,我得到一個CrossThreadMessagingException。如果我不調試但只是運行代碼,一切都很好。如果我將該集合轉換爲列表之前,將其分配給processes並在調試期間使用Count屬性也是很好的。

究竟是什麼CrossThreadMessagingException和爲什麼IEnumerable方法導致這樣的異常?


編輯:提供關於異常的更多信息。

消息:異常 'Microsoft.VisualStudio.Debugger.Runtime.CrossThreadMessagingException' 發生

來源:Microsoft.VisualStudio.Debugger.Runtime

堆棧跟蹤:

在Microsoft.VisualStudio.Debugger。 Runtime.Main.ThrowCrossThreadMessageException(字符串formatString的)

在Microsoft.Win32.NativeMethods.GetWindowTextLength(HandleRef HWND)

在System.Diagnostics.Process.get_MainWindowTitle()

+0

CrossThreadMessagingException說什麼? –

+0

嗯,不尋常。調試器正在攔截本地Windows調用。什麼版本的Visual Studio這樣做?什麼樣的項目? 64位操作系統?遠程調試器? –

回答

3

這可能完全是錯誤的,但我猜想這是推遲枚舉與WhereArrayIterator的混合物,調試器試圖枚舉呢?

我感覺,即時窗口試圖列舉您的結果,它在另一個線程(這是導致CrossThreadMessagingException)這樣做。

當您撥打ToList時,它不會執行此操作,因爲ToList會導致枚舉立即運行並將結果連接到列表中。這是在您嘗試在即時窗口中使用Count方法之前完成的。

當您使用Count()沒有ToList調用,它迫使WhereArrayIterator(這是你的Where方法調用的返回值)來枚舉,然後試圖從另一個線程訪問您的LAMDA委託。

在測試中,你實際上可以通過直接枚舉的WhereArrayIterator其他情況,所以我覺得這是你的特定使用情況下,如果你試圖枚舉在Process類型,我認爲在內部使使用Win32 API調用。

在內部,Process.MainWindowTitle屬性爲其值使用延遲加載。它實際上並沒有讓這個調用來獲取信息,直到第一次訪問屬性(,而且它沒有鎖定,所以如果有多個線程訪問該代碼區域,它不是原子的,因此存在競爭條件的繼承風險 - 無論如何,這無關緊要,因爲它是隻讀屬性,其價值應該總是相同的)。

[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] 
[MonitoringDescription("ProcessMainWindowTitle")] 
public string MainWindowTitle 
{ 
    get 
    { 
    if (this.mainWindowTitle == null) 
    { 
     IntPtr mainWindowHandle = this.MainWindowHandle; 
     if (mainWindowHandle == (IntPtr) 0) 
     { 
     this.mainWindowTitle = string.Empty; 
     } 
     else 
     { 
     StringBuilder lpString = new StringBuilder(Microsoft.Win32.NativeMethods.GetWindowTextLength(new HandleRef((object) this, mainWindowHandle)) * 2); 
     Microsoft.Win32.NativeMethods.GetWindowText(new HandleRef((object) this, mainWindowHandle), lpString, lpString.Capacity); 
     this.mainWindowTitle = ((object) lpString).ToString(); 
     } 
    } 
    return this.mainWindowTitle; 
    } 
} 

當它第一次被訪問時,該屬性使Win32調用來獲取窗口文本。我相信這是它似乎墮落的地方。 但是它只是在您的WhereArrayIterator實例中使用延遲枚舉時纔會發生。

這是一個盲目的猜測是誠實的!

+0

感謝您的詳細信息。 – Moss