是什么原因导致Winforms无声地丢弃未处理的exception(没有尝试/捕获)?

我正在为我的winforms控件添加新function,其中一部分需要一个曾经常用的变量现在是可选的(如果它为null,则从第二个源获取数据)。 我做了一些更改并运行了我的表单,但却发现没有发生任何事情,甚至是之前有效的function。 困惑我介入了代码并发现我的Winforms用户控件在遇到我的变量时抛出了NullReferenceException ,但是在UI中没有抛出任何错误。

我的设置是我有一个带有combobox的UserControl 。 当用户更改该combobox时,它会在第一个控件具有的面板中加载辅助UserControl 。 第二个控件就是抛出exception。

以下是代码路径:

  private void cmbActionType_SelectedIndexChanged(object sender, EventArgs e) { if (_loading) return; // ActionType was changed, update the action.ActionType value if (cmbActionType.SelectedItem != null) { if (cmbActionType.SelectedItem.ToString() == SETVALUE_OPTION) _action.ActionType = ActionTypes.SetValue; else if (cmbActionType.SelectedItem.ToString() == CHECKVALUE_OPTION) _action.ActionType = ActionTypes.CheckValue; else _action.ActionType = ActionTypes.CustomAction; } RefreshActionPanel(); _editor.DataModified(); } private void RefreshActionPanel() { // Control defaults AnchorStyles styles = AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right | AnchorStyles.Top; UserControl subControl = null; // Clear the currently active control pnlActionDetails.Controls.Clear(); // Determine what type of control to load in the panel if (cmbActionType.SelectedItem != null && cmbCaseType.SelectedItem != null) { // SetValue or CheckValue actions if (cmbActionType.SelectedItem.ToString() == CHECKVALUE_OPTION || cmbActionType.SelectedItem.ToString() == SETVALUE_OPTION) { if (_caseTypeMap.ContainsKey(cmbCaseType.SelectedItem.ToString())) subControl = new SetCheckActionControl(_action, _editor, _caseTypeMap[cmbCaseType.SelectedItem.ToString()]); } // CustomAction action type else { // Check if the requested case is a type or defined in a script if (_caseTypeMap.ContainsKey(cmbCaseType.SelectedItem.ToString())) { subControl = new CustomActionControl(_action, _editor, _caseTypeMap[cmbCaseType.SelectedItem.ToString()]); } else if (_editor.ScriptDefinitions.Any(x => x.CaseName == cmbCaseType.SelectedItem.ToString())) { var definitions = _editor.ScriptDefinitions.Where(x => x.CaseName == cmbCaseType.SelectedItem.ToString()).ToList(); subControl = new CustomActionControl(_action, _editor, definitions); } } } if (subControl != null) { subControl.Anchor = styles; subControl.Height = pnlActionDetails.Height; subControl.Width = pnlActionDetails.Width; pnlActionDetails.Controls.Add(subControl); } } public CustomActionControl(TestAction action, fmEditor editor, IList scriptDefinitions) : base(action, editor) { _loading = true; InitializeComponent(); _scriptDefinitions = scriptDefinitions; PopulateActionList(); SetupDataGrid(); _loading = false; } private void SetupDataGrid() { // Clear the current contents of the datagrid grdParameters.Rows.Clear(); if (cmbAction.SelectedItem == null) return; // Retrieve the action code from the drop down string actionCode = cmbAction.SelectedValue.ToString(); // Check if any paramters are available for this action if (!_availableActionParameters.ContainsKey(actionCode)) return; // Add a new row for each parameter available for this action foreach (string param in _availableActionParameters[actionCode]) { string display = param; // Determine if the parameter has a display string if (_formInstance.CodeDisplayMap.ContainsCode(param)) display = _formInstance.CodeDisplayMap.GetDisplayStringFromCode(param); // Create the array for the row, with an empty string as the current value string[] row = { display, string.Empty }; // Check if the current action uses this action code. // If so, retrieve the value for this parameter and use it in the row // Note: Case-INsensitive comparison must be performed here if (_action.Attributes["action"].Equals(actionCode, StringComparison.CurrentCultureIgnoreCase)) if (_action.Attributes.ContainsKey(param)) row[1] = _action.Attributes[param]; grdParameters.Rows.Add(row); } } 

NullReferenceException来自SetupDataGrid()方法,其中_formInstance 。 但是,通常当应用程序遇到未处理的exception时,JIT系统会抛出一条错误消息(如您​​所见,除非我是盲目的,否则不会使用try/catch语句)。

为什么我的winforms应用程序没有显示exception的迹象。 我宁愿发生未处理的exception消息,而不是发生任何事情,因为这使得用户更难以了解重要的错误(相反,它没有响应他们的命令)


编辑:为了澄清,因为似乎有一些混乱,我不关心在Visual Studio中调试时打破这个exception。 事实上,应用程序不应该隐藏未处理的exception,并且我的应用程序应该崩溃(或者更确切地说显示JIT消息发生了未处理的exception),即使不在Visual Studio之外的调试模式下也是如此。

这不是调试时间问题,而是生产运行时问题。 如果此代码抛出一个OutOfMemoryException ,我需要它不要被忽略。 现在它被忽略了。

如果您在Maintry / catch ,或者如果您有ThreadException处理程序,则可以捕获它们。 另请查看SetUnhandledExceptionMode

请注意,如果它们被Main捕获,您的程序将会以静默方式退出。 ThreadException可以“捕获”并忽略它们。

编辑:由于在Common Language Runtime Exceptions下取消选中“ Thrown ”框时调试器不会中断,因此它会被Windows窗体的代码捕获。 这并不理想,但很多BCL都是这样做的。 您不必担心它会捕获OutOfMemoryException或类似的东西; BCL应该只捕获它期望的exception ( 令人烦恼的例外 )。

需要说明的是,例外并非“未处理”。 它由BCL代码处理。

从Visual Studio的菜单栏转到Debug->Exceptions... (如果使用默认快捷键Ctrl-D, E则为Ctrl-D, E ),并选中Common Language Runtime Exceptions下的Debug->Exceptions...框。 这将导致程序在exception中断,即使它们位于try / catch块中。 然后,您可以向前迈出一步,查看代码跳转到下一条指令的位置。 这应该会带你到隐藏你的exception的catch块。

它可能会跳转到.NET代码以获取catch,您可以转到Debug->Options and Settings..然后Enable .NET framework Source Stepping来查看它跳转到的内容。


这是一个在代码中捕获unhandeled execptions的示例

 static class Program { ///  /// The main entry point for the application. ///  [STAThread] static void Main() { Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); Application.ThreadException += new System.Threading.ThreadExceptionEventHandler(Application_ThreadException); Application.Run(new Form1()); MessageBox.Show("0"); } static void Application_ThreadException(object sender, System.Threading.ThreadExceptionEventArgs e) { MessageBox.Show("1"); } } public partial class Form1 : Form { public Form1() { InitializeComponent(); } private void button1_Click(object sender, EventArgs e) { throw new ArgumentNullException(); } } 

单击按钮,出现1,程序仍然应该运行。

但是正如我在上一篇评论中所说的那样,检查是否在Debug-> Exceptions中检查了用户unhandeled(可能是取消选中并重新检查),它可能会解决您的初始问题。