O que faz com que o Winforms descarte silenciosamente exceções não tratadas (sem tentativa / captura)?
Estou no meio de adicionar novas funcionalidades aos meus controles winforms, e parte disso exige que uma variável que antes era usada agora seja opcional agora (se for nula, obtenha os dados de uma segunda fonte). Fiz algumas alterações e executei meu formulário, apenas para descobrir que nada estava acontecendo, até mesmo a funcionalidade que funcionava anteriormente. Confuso, percorri o código e descobri que meu controle de usuário do Winforms estava lançando umNullReferenceException
quando encontrou minha variável, mas na interface do usuário nenhum erro estava sendo gerad
Minha configuração é que tenho umUserControl
com uma caixa de combinação. Quando o usuário altera essa caixa de combinação, ele carrega um @ secundárUserControl
em um painel que o primeiro controle possui. O segundo controle é o que está lançando a exceçã
Aqui estão os caminhos do 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);
}
}
ONullReferenceException
vem doSetupDataGrid()
método em que_formInstance
está sendo chamado. No entanto, geralmente quando um aplicativo encontra uma exceção não tratada, o sistema JIT lança uma mensagem de erro dizendo isso (e como você pode ver, não hátry/catch
eclarações usadas a menos que eu seja cego
Por que meu aplicativo winforms não mostra sinais de exceção? Prefiro que ocorra uma mensagem de exceção não tratada, em vez de não acontecer nada, pois isso dificulta que os usuários saibam que algo crítico deu errado (em vez de não responder aos comandos)
Editar Para esclarecer, uma vez que parece haver alguma confusão, NÃO me importo em quebrar essa exceção no visual studio ao depurar. O fato é que o aplicativo não deve ocultar exceções sem tratamento, e meu aplicativo deve falhar (ou melhor, mostrar a mensagem JIT de que ocorreu uma exceção sem tratamento), mesmo quando não estiver no modo de depuração fora do visual studiEsta não é uma questão de tempo de depuração, mas uma questão de tempo de execução da produção. Se esse código gerar umOutOfMemoryException
por exemplo, preciso que ele não seja ignorado silenciosamente. No momento, está sendo ignorado.