una - try catch c# ejemplo
¿Qué hace que los Winforms descarten silenciosamente las excepciones no controladas(sin try/Catches)? (2)
Estoy en el medio de agregar nuevas funcionalidades a mis controles de winforms, y parte de eso requiere que una variable que alguna vez fue utilizada sea ahora opcional (si es nula, obtenga los datos de una segunda fuente). Hice algunos cambios y ejecuté mi formulario, solo para descubrir que no estaba sucediendo nada, incluso la funcionalidad que funcionó previamente. Confundido di un paso adelante en el código y descubrí que mi control de usuario de Winforms arrojaba una NullReferenceException
cuando se encontró con mi variable, pero en la interfaz de usuario no se lanzaron errores.
Mi configuración es Tengo un UserControl
con un cuadro combinado. Cuando el usuario cambia ese cuadro combinado, carga un UserControl
secundario en un panel que tiene el primer control. El segundo control es lo que arroja la excepción.
Aquí están las rutas de código:
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<TcScriptDefinition> 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
proviene del método SetupDataGrid()
donde se llama a _formInstance
. Sin embargo, generalmente cuando una aplicación encuentra una excepción no controlada, el sistema JIT arroja un mensaje de error que dice eso (y como puede ver, no hay declaraciones try/catch
usadas a menos que sea ciego).
¿Por qué mi aplicación winforms no muestra signos de que se produzca una excepción? Prefiero que se produzca un mensaje de excepción no controlada en lugar de que no ocurra nada, ya que eso hace que sea más difícil para los usuarios saber que algo crítico salió mal (en lugar de no responder a sus comandos)
Editar: para aclarar, ya que parece haber cierta confusión, NO me importa romper esta excepción en Visual Studio cuando se depura. El hecho es que la aplicación no debe ocultar excepciones no controladas, y mi aplicación debería bloquearse (o más bien mostrar el mensaje JIT de que se produjo una excepción no controlada), incluso cuando no esté en modo de depuración fuera de Visual Studio. Esta no es una pregunta de tiempo de depuración sino una pregunta de tiempo de ejecución de producción. Si este código arroja una OutOfMemoryException
por ejemplo, necesito que no se ignore silenciosamente. En este momento está siendo ignorado.
Se pueden capturar si tiene una try
/ catch
en su Main
, o si tiene un controlador ThreadException
. También echa un vistazo a SetUnhandledExceptionMode
.
Tenga en cuenta que si están atrapados en Main
, su programa simplemente saldrá en silencio. ThreadException
puede "atrapar" e ignorarlos.
EDITAR: Debido a que el depurador no se rompe cuando deselecciona la casilla para Thrown
bajo Common Language Runtime Exceptions
, está siendo capturado por el código para Windows Forms. Esto no es ideal, pero una gran parte del BCL hace esto. No necesita preocuparse por detectar OutOfMemoryException
o algo por el estilo; el BCL solo debería capturar las excepciones que espera ( molestas excepciones ).
Para ser claros, la excepción no es "no controlada". Es manejado por el código BCL.
Vaya a Debug->Exceptions...
( Ctrl-D, E
si está utilizando accesos directos predeterminados) desde su barra de menú en Visual Studio y marque la casilla Thrown
en Common Language Runtime Exceptions
. Esto hará que su programa rompa las excepciones incluso si están en un bloque try / catch. Luego puede dar un paso adelante y ver hacia dónde se dirige el código para la siguiente instrucción. Eso debería llevarte al bloque catch que está ocultando tu excepción.
Puede estar ingresando en el código .NET para la captura, puede ir a Debug->Options and Settings..
y activar Enable .NET framework Source Stepping
para ver en qué está saltando.
Aquí hay un ejemplo de cómo capturar las ejecuciones no modificadas en el código
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[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();
}
}
Haga clic en el botón y aparecerá 1, el programa debería seguir ejecutándose después.
Sin embargo, como dije en mi último comentario, verifique que el usuario sin cambiar esté marcado (tal vez desmarque y vuelva a verificar) en Debug-> Exceptions primero, puede resolver su problema inicial.