Eu estava escrevendo este código:
private static Expression<Func<Binding, bool>> ToExpression(BindingCriterion criterion)
{
switch (criterion.ChangeAction)
{
case BindingType.Inherited:
var action = (byte)ChangeAction.Inherit;
return (x => x.Action == action);
case BindingType.ExplicitValue:
var action = (byte)ChangeAction.SetValue;
return (x => x.Action == action);
default:
// TODO: Localize errors
throw new InvalidOperationException("Invalid criterion.");
}
}
E ficou surpreso ao encontrar um erro de compilação:
Uma variável local denominada 'ação' já está definida neste escopo
Foi uma questão bastante fácil de resolver; apenas se livrar do segundo var
fez o truque.
Evidentemente, as variáveis declaradas em case
blocos têm o escopo do pai switch
, mas estou curioso para saber por que isso acontece. Dado que C # não permite a execução de cair através de outros casos (que requer break
, return
, throw
, ou goto case
declarações no final de cada case
bloco), parece bastante estranho que permitiria declarações de variáveis dentro de um case
para ser usado ou conflito com as variáveis em qualquer outra case
. Em outras palavras, as variáveis parecem passar por case
instruções, embora a execução não possa. O C # esforça-se ao máximo para promover a legibilidade, proibindo algumas construções de outros idiomas que sejam confusas ou que sejam facilmente abusadas. Mas isso parece apenas causar confusão. Considere os seguintes cenários:
Se fosse alterá-lo para isso:
case BindingType.Inherited: var action = (byte)ChangeAction.Inherit; return (x => x.Action == action); case BindingType.ExplicitValue: return (x => x.Action == action);
Recebo " Uso da variável local não atribuída 'action' ". Isso é confuso, porque em qualquer outra construção em C # que eu possa pensar
var action = ...
inicializaria a variável, mas aqui ela simplesmente a declara.Se eu fosse trocar os casos assim:
case BindingType.ExplicitValue: action = (byte)ChangeAction.SetValue; return (x => x.Action == action); case BindingType.Inherited: var action = (byte)ChangeAction.Inherit; return (x => x.Action == action);
Recebo " Não é possível usar a variável local 'action' antes de ser declarada ". Portanto, a ordem dos blocos de casos parece ser importante aqui de uma maneira que não é totalmente óbvia - normalmente eu poderia escrevê-los em qualquer ordem que desejasse, mas como os
var
itens devem aparecer no primeiro bloco em queaction
é usado, tenho que ajustar oscase
blocos. adequadamente.Se fosse alterá-lo para isso:
case BindingType.Inherited: var action = (byte)ChangeAction.Inherit; return (x => x.Action == action); case BindingType.ExplicitValue: action = (byte)ChangeAction.SetValue; goto case BindingType.Inherited;
Não recebo nenhum erro, mas, em certo sentido, parece que a variável está recebendo um valor antes de ser declarada.
(Embora eu não consiga pensar em nenhum momento em que você realmente queira fazer isso - eu nem sabia quegoto case
existia antes de hoje)
Então, minha pergunta é: por que os designers de C # não deram aos case
blocos seu próprio escopo local? Existem razões históricas ou técnicas para isso?
switch
- eu só estou curioso sobre o raciocínio por trás desse design.
break
não seja possível em C #.
action
variável antes daswitch
declaração ou coloque cada caso em seu próprio aparelho, e você obterá um comportamento sensato.