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;
  }
}