Trace.Assert没有破坏,也没有显示消息框

我有一个WPF应用程序,我在Canvas上移动数据。 当我尝试使用鼠标像怪物一样移动数据时,问题就出现了。

这是动作的顺序:

  • 将触发canvas上的MouseMove
  • 在MouseMove中,我更改了一些数据
  • 一个Trace.Assert失败。 调试器不会中断,消息框也不会中断
  • 另一个MouseMove被触发
  • 数据再次更改
  • 由于集合中的重入检查而抛出exception。 调试器打破了。 从未显示Assert消息框。

这里的一个大问题是我可以回到断言,但它不是断言失败时的数据,而是最后修改过的数据……所以基本上我无法正确调试。

这是堆栈跟踪,从第一个MouseMove开始(注意ShowMessageBoxAssert以及它仍在继续……):

   .Models.FCurve.MoveKey(int keyIndex = 3,double keyTime = 1182.0)第199行C#.Models.FCurve.KeyTimeChanged(Models.FCurveKey timeChangeKey = {Models.FCurveKey})第186行+ 0x2d字节C#.Models.FCurve.AddKeyToArray .AnonymousMethod(object sender = {Models.FCurveKey},System.EventArgs args = {System.EventArgs})第163行+ 0x11字节C#[本机到托管转换] [管理到本机转换] .Models.FCurveKey.OnTimeChanged()行45 + 0x14字节C#.Models.FCurveKey..ctor.AnonymousMethod(object sender = {FCurveEditorTestApp.Impl.FCurveKeyImpl},System.EventArgs args = {System.EventArgs})第18行+ 0x8字节C#[本机到托管转换] [管理到本机转换] FCurveEditorTestApp.exe!FCurveEditorTestApp.Impl.FCurveKeyImpl.OnTimeChanged()第43行+ 0x14字节C#FCurveEditorTestApp.exe!FCurveEditorTestApp.Impl.FCurveKeyImpl.Time.set(double value = 1182.0)第34行+ 0x8字节C#。 Models.FCurveKey.Time.set(double value = 1182.0)第36行+ 0x1b字节C#.ViewModels.CurveKeyVi  ewModel.X.set(double value = 1182.0)第32行+ 0x2b字节C#.ViewModels.CurveAreaViewModel.MoveSelectedItem.AnonymousMethod(ViewModels.CurveKeyViewModel key = {ViewModels.CurveKeyViewModel})第127行+ 0x2d字节C#Collections.CollectionHelper.ForEach(系统.Collections.Generic.IEnumerable source = {System.Linq.Enumerable.OfTypeIterator},System.Action action = {Method = {Void b__8(ViewModels.CurveKeyViewModel)}})第31行+ 0xe字节C#.ViewModels.CurveAreaViewModel.MoveSelectedItem( double deltaX = 693.0,double deltaY = 35.0)第126行+ 0x63字节C#.Views.CurveAreaView._AreaCanvas_MouseMove(object sender = {System.Windows.Controls.Canvas},System.Windows.Input.MouseEventArgs e = {System.Windows。 Input.MouseEventArgs})行195 + 0x2d字节C#PresentationCore.dll!System.Windows.Input.MouseEventArgs.InvokeEventHandler(System.Delegate genericHandler,object genericTarget)+ 0x34 bytes PresentationCore.dll!System.Windows.RoutedEventArgs.InvokeHandler(System。委托处理程序,对象t  arget)+ 0x27 bytes PresentationCore.dll!System.Windows.RoutedEventHandlerInfo.InvokeHandler(object target,System.Windows.RoutedEventArgs routedEventArgs)+ 0x3e bytes PresentationCore.dll!System.Windows.EventRoute.InvokeHandlersImpl(object source = {System.Windows。 Controls.Canvas},System.Windows.RoutedEventArgs args = {System.Windows.Input.MouseEventArgs},bool reRaised = false)+ 0x1bf bytes PresentationCore.dll!System.Windows.UIElement.RaiseEventImpl(System.Windows.DependencyObject sender = { System.Windows.Controls.Canvas},System.Windows.RoutedEventArgs args = {System.Windows.Input.MouseEventArgs})+ 0x79 bytes PresentationCore.dll!System.Windows.UIElement.RaiseEvent(System.Windows.RoutedEventArgs args = {System .Windows.Input.MouseEventArgs},bool trusted)+ 0x35 bytes PresentationCore.dll!System.Windows.Input.InputManager.ProcessStagingArea()+ 0x311 bytes PresentationCore.dll!System.Windows.Input.InputManager.ProcessInput(System.Windows。 Input.InputEventArgs输入)+ 0x42字节  PresentationCore.dll!System.Windows.Input.InputProviderSite.ReportInput(System.Windows.Input.InputReport inputReport)+ 0x62 bytes PresentationCore.dll!System.Windows.Interop.HwndMouseInputProvider.ReportInput(System.IntPtr hwnd,System.Windows.Input .InputMode模式,int timestamp,System.Windows.Input.RawMouseActions动作,int x,int y,int wheel)+ 0x2e2 bytes PresentationCore.dll!System.Windows.Interop.HwndMouseInputProvider.FilterMessage(System.IntPtr hwnd = 2628604,int msg = 512,System.IntPtr wParam = 1,System.IntPtr lParam = 30409804,ref bool handling = false)+ 0x22b bytes PresentationCore.dll!System.Windows.Interop.HwndSource.InputFilterMessage(System.IntPtr hwnd = 2628604,int msg = 512,System.IntPtr wParam = 1,System.IntPtr lParam = 30409804,ref bool handling = false)+ 0x75 bytes WindowsBase.dll!MS.Win32.HwndWrapper.WndProc(System.IntPtr hwnd = 2628604,int msg = 512, System.IntPtr wParam = 1,System.IntPtr lParam = 30409804,ref bool handling = false)+ 0xbe bytes Win  dowsBase.dll!MS.Win32.HwndSubclass.DispatcherCallbackOperation(object o)+ 0x7a bytes WindowsBase.dll!System.Windows.Threading.ExceptionWrapper.InternalRealCall(System.Delegate callback = {Method = {System.Object DispatcherCallbackOperation(System.Object) },object args = {MS.Win32.HwndSubclass.DispatcherOperationCallbackParameter},bool isSingleParameter = true)+ 0x8a bytes WindowsBase.dll!System.Windows.Threading.ExceptionWrapper.TryCatchWhen(object source = {System.Windows.Threading.Dispatcher} ,System.Delegate回调,对象args,bool isSingleParameter,System.Delegate catchHandler = null)+ 0x4a bytes WindowsBase.dll!System.Windows.Threading.Dispatcher.WrappedInvoke(System.Delegate回调,对象args,bool isSingleParameter,System.Delegate catchHandler)+ 0x44字节WindowsBase.dll!System.Windows.Threading.Dispatcher.InvokeImpl(System.Windows.Threading.DispatcherPriority priority,System.TimeSpan timeout,System.Delegate方法,object args,bool isSingleParameter)+ 0x91  bytes WindowsBase.dll!System.Windows.Threading.Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority priority,System.Delegate method,object arg)+ 0x40 bytes WindowsBase.dll!MS.Win32.HwndSubclass.SubclassWndProc(System.IntPtr hwnd = 2628604,int msg = 512,System.IntPtr wParam = 1,System.IntPtr lParam = 30409804)+ 0xdc bytes [本机到托管转换] [管理到本机转换] System.dll!System.Diagnostics.AssertWrapper.ShowMessageBoxAssert( string stackTrace,string message,string detailMessage)+ 0x103 bytes System.dll!System.Diagnostics.DefaultTraceListener.Fail(string message,string detailMessage)+ 0xb2 bytes System.dll!System.Diagnostics.DefaultTraceListener.Fail(string message)+ 0xa bytes System.dll!System.Diagnostics.TraceInternal.Fail(string message =“”)+ 0xb6 bytes System.dll!System.Diagnostics.Trace.Assert(bool condition)+ 0x1c bytes .ViewModels.CurvePathViewModel.CurvePathViewModel(Models.FCurveKey startKey = {Models.FCurveKey},Models.FCurveKey en  dKey = {Models.FCurveKey},ViewModels.IInterpolationProvider interpolatorProvider = {ViewModels.InterpolationInfoProvider})第29行+ 0x4e字节C#.ViewModels.CurvePathViewModel.CurvePathViewModel(ViewModels.CurveKeyViewModel startKey = {ViewModels.CurveKeyViewModel},ViewModels.CurveKeyViewModel endKey = {ViewModels .CurveKeyViewModel},ViewModels.IInterpolationProvider interpolatorProvider = {ViewModels.InterpolationInfoProvider})第20行+ 0x81字节C#.ViewModels.CurveViewModel.UpdateSegmentForKey(ViewModels.CurveKeyViewModel key = {ViewModels.CurveKeyViewModel})第215行+ 0x41字节C#.ViewModels.CurveViewModel。 KeyViewModelsChanged(object sender = Count = 13,System.Collections.Specialized.NotifyCollectionChangedEventArgs e = {System.Collections.Specialized.NotifyCollectionChangedEventArgs})第187行+ 0x30字节C#[本机到托管转换] [管理到本机转换] WindowsBase.dll! System.Collections.ObjectModel.ObservableCollection.OnCollectionChanged(System.Collect  ions.Specialized.NotifyCollectionChangedEventArgs e)+ 0x50 bytes WindowsBase.dll!System.Collections.ObjectModel.ObservableCollection.OnCollectionChanged(System.Collections.Specialized.NotifyCollectionChangedAction action,object item,int index,int oldIndex)+ 0x34 bytes WindowsBase.dll!System .Collections.ObjectModel.ObservableCollection.MoveItem(int oldIndex,int newIndex)+ 0x6f bytes WindowsBase.dll!System.Collections.ObjectModel.ObservableCollection.Move(int oldIndex,int newIndex)+ 0xe bytes Collections.CollectionSynchronizer._SourceList_CollectionChanged(object sender = Count = 13,System.Collections.Specialized.NotifyCollectionChangedEventArgs e = {System.Collections.Specialized.NotifyCollectionChangedEventArgs})第239行+ 0x45字节C#[本机到托管转换] [管理到本机转换] WindowsBase.dll!System.Collections.ObjectModel .ReadOnlyObservableCollection.OnCollectionChanged(System.Collections.Specialized.NotifyCollectionChangedEventArgs args)+ 0x1d bytes W  indowsBase.dll!System.Collections.ObjectModel.ReadOnlyObservableCollection.HandleCollectionChanged(object sender,System.Collections.Specialized.NotifyCollectionChangedEventArgs e)+ 0xe bytes [本机到托管转换] [托管到本机转换] WindowsBase.dll!System.Collections.ObjectModel .ObservableCollection.OnCollectionChanged(System.Collections.Specialized.NotifyCollectionChangedEventArgs e)+ 0x50 bytes WindowsBase.dll!System.Collections.ObjectModel.ObservableCollection.OnCollectionChanged(System.Collections.Specialized.NotifyCollectionChangedAction action,object item,int index,int oldIndex)+ 0x34字节WindowsBase.dll!System.Collections.ObjectModel.ObservableCollection.MoveItem(int oldIndex,int newIndex)+ 0x6f bytes WindowsBase.dll!System.Collections.ObjectModel.ObservableCollection.Move(int oldIndex,int newIndex)+ 0xe bytes .Models .FCurve.MoveKey(int keyIndex = 1,double keyTime = 489.0)第199行+ 0x19字节C#.Models.FCurve.KeyTimeChanged(Models.FCurveKey t  imeChangeKey = {Models.FCurveKey})第186行+ 0x2d字节C#.Models.FCurve.AddKeyToArray.AnonymousMethod(object sender = {Models.FCurveKey},System.EventArgs args = {System.EventArgs})第163行+ 0x11字节C#[本机到托管转换] [管理到本机转换] .Models.FCurveKey.OnTimeChanged()第45行+ 0x14字节C#.Models.FCurveKey..ctor.AnonymousMethod(object sender = {FCurveEditorTestApp.Impl.FCurveKeyImpl},System.EventArgs args = {System.EventArgs})第18行+ 0x8字节C#[本机到托管转换] [管理到本机转换] FCurveEditorTestApp.exe!FCurveEditorTestApp.Impl.FCurveKeyImpl.OnTimeChanged()第43行+ 0x14字节C#FCurveEditorTestApp.exe!FCurveEditorTestApp。 Impl.FCurveKeyImpl.Time.set(double value = 489.0)第34行+ 0x8字节C#.Models.FCurveKey.Time.set(double value = 489.0)第36行+ 0x1b字节C#.ViewModels.CurveKeyViewModel.X.set(double value = 489.0)第32行+ 0x2b字节C#.ViewModels.CurveAreaViewModel.MoveSelectedItem.AnonymousMethod(查看  Models.CurveKeyViewModel key = {ViewModels.CurveKeyViewModel})第127行+ 0x2d字节C#Collections.CollectionHelper.ForEach(System.Collections.Generic.IEnumerable source = {System.Linq.Enumerable.OfTypeIterator},System.Action action = {Method = {Void b__8(ViewModels.CurveKeyViewModel)}})第31行+ 0xe字节C#.ViewModels.CurveAreaViewModel.MoveSelectedItem(double deltaX = 82.0,double deltaY = -9.0)第126行+ 0x63字节C#Views.CurveAreaView._AreaCanvas_MouseMove(object sender = {System.Windows.Controls.Canvas},System.Windows.Input.MouseEventArgs e = {System.Windows.Input.MouseEventArgs})第195行+ 0x2d字节C# 

问题是:为什么会发生这种情况,我该怎么办才能让它在Assert时间突破?

我想过使用exception,也许是为了调试,但它确实是我需要的断言。 我正在考虑我的所有其他Asserts,而不需要总是将它们转换为exception进行调试…

您可以在AppDomain范围内(在应用程序范围内,如果您的应用程序只有一个AppDomain)通过编写自己的TraceListener

首先创建一个包含ExceptionTraceListener类的类库项目MyTraceListeners.dll

 public class ExceptionTraceListener : TraceListener { public override void Write(string message) { // Do nothing } public override void Fail(string message) { Debugger.Break(); // or if you prefer, throw new Exception(...) } public override void Fail(string message, string detailMessage) { Debugger.Break(); // or if you prefer, throw new Exception(...) } } 

现在,您可以通常的方式在应用程序的.config文件中注册此TraceListener

  ...  ...         

当您使用这些.config文件条目运行应用程序时,调试器将在每个失败的断言时立即中断。

另请注意此配置文件中的以清除Machine.config列出的任何默认TraceListeners 。 这很重要,因为默认的TraceListener将在您之前接收调用并仍然弹出MessageBox

我以前见过类似的东西,当时工作的一种解决方法是添加一个if语句与assert相同的条件,但是否定的,结合在调试器中设置的断点在if块的then块中的语句中。