C# 调试期间IEnumerable vs IList和奇怪的CrossThreadMessagingException
初始代码如下:C# 调试期间IEnumerable vs IList和奇怪的CrossThreadMessagingException,c#,.net,debugging,internals,C#,.net,Debugging,Internals,初始代码如下: var processes = Process.GetProcesses().Where(p => p.MainWindowTitle.ToUpperInvariant().Contains("FOO")); 在调试过程中,如果我尝试在即时窗口窗格中调用processs上的Count(),或者检查本地窗格中的“Results View”,我会得到一个CrossThreadMessaginException。如果我不调试,只是运行代码,一切都很好。如果在将集合分配给进程之前
var processes = Process.GetProcesses().Where(p => p.MainWindowTitle.ToUpperInvariant().Contains("FOO"));
在调试过程中,如果我尝试在即时窗口窗格中调用processs
上的Count()
,或者检查本地窗格中的“Results View”,我会得到一个CrossThreadMessaginException
。如果我不调试,只是运行代码,一切都很好。如果在将集合分配给进程
之前将其转换为列表,并在调试期间使用计数
属性,也可以
CrossThreadMessagineException
究竟是什么?为什么IEnumerable
方法会导致这种异常
编辑:提供有关异常的更多信息 消息:发生异常“Microsoft.VisualStudio.Debugger.Runtime.CrossThreadMessaginException” 来源:Microsoft.VisualStudio.Debugger.Runtime 堆栈跟踪: 位于Microsoft.VisualStudio.Debugger.Runtime.Main.ThrowCrossThreadMessageException(字符串格式字符串) 位于Microsoft.Win32.NativeMethods.GetWindowTextLength(HandleRef hWnd)
在System.Diagnostics.Process.get_MainWindowTitle()中,这可能是完全错误的,但我推测这是延迟枚举与
wherearayiterator
的混合,调试器试图枚举它
我感觉到,当即时窗口试图枚举您的结果时,它是在另一个线程上这样做的(这导致了CrossThreadMessaginException
)
当您调用ToList
时,它不会这样做,因为ToList
会导致枚举立即运行并将结果连接到列表中。这是在尝试使用即时窗口中的Count
方法之前完成的
当您使用Count()
而不使用ToList
调用时,它会强制whererrayiterator
(它是Where
方法调用的返回值)枚举,然后它会尝试从另一个线程访问lamda委托
在测试中,您实际上可以通过immediate枚举whererayiterator
的其他实例,因此我认为这是您的特定用例,您试图枚举进程
类型,我认为它在内部使用Win32 API进行调用
在内部,Process.MainWindowTitle
属性使用延迟加载作为其值。在第一次访问属性之前,它实际上不会调用以获取信息(而且,它这样做没有锁定,因此如果有多个线程访问代码的该区域,那么它不是原子的,因此存在竞争条件的继承风险——不管怎样,这都不重要,因为它是只读属性,谁的值应该始终相同)
第一次访问时,该属性会发出Win32调用以获取窗口文本。我相信这就是它似乎要崩溃的地方。但是只有在对wherearayiterator
实例使用延迟枚举时,它才会崩溃
老实说,这完全是瞎猜!CrossThreadMessagingException到底说了什么?嗯,不寻常。调试器正在拦截本机Windows调用。Visual Studio的哪个版本会这样做?什么样的项目?64位操作系统?远程调试器?感谢提供详细信息。
[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;
}
}