Pisałem ten kod:
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.");
}
}
Był zaskoczony, gdy znalazł błąd kompilacji:
Zmienna lokalna o nazwie „akcja” jest już zdefiniowana w tym zakresie
Rozwiązanie problemu było dość łatwe; po prostu pozbycie się drugiego var
rozwiązało problem.
Oczywiście zmienne zadeklarowane w case
blokach mają zakres elementu nadrzędnego switch
, ale jestem ciekawy, dlaczego tak jest. Biorąc pod uwagę, że C # nie zezwala na wykonanie spadać przez innych przypadkach (to wymaga break
, return
, throw
czy goto case
sprawozdanie na koniec każdego case
bloku), wydaje się dość dziwne, że pozwoliłoby to deklaracje zmiennych wewnątrz jeden case
do wykorzystania lub konflikt ze zmiennymi w jakikolwiek inny case
. Innymi słowy, zmienne wydają się przechodzić przez case
instrukcje, nawet jeśli wykonanie nie może. C # bardzo się stara, aby promować czytelność, zakazując niektórych konstrukcji innych języków, które są mylące lub łatwo nadużywane. Ale wydaje się, że to po prostu spowoduje zamieszanie. Rozważ następujące scenariusze:
Gdyby to zmienić na to:
case BindingType.Inherited: var action = (byte)ChangeAction.Inherit; return (x => x.Action == action); case BindingType.ExplicitValue: return (x => x.Action == action);
Pojawia się komunikat „ Zastosowanie nieprzypisanej zmiennej lokalnej„ akcja ”. Jest to mylące, ponieważ w każdym innym konstrukcie w języku C #, o którym mogę pomyśleć
var action = ...
, zainicjuje zmienną, ale tutaj po prostu ją deklaruje.Gdybym zamienił takie przypadki:
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);
Otrzymuję komunikat „ Nie można użyć zmiennej lokalnej„ akcja ”, zanim nie zostanie zadeklarowana ”. Tak więc kolejność bloków skrzynek wydaje się tutaj ważna w sposób, który nie jest do końca oczywisty - normalnie mógłbym napisać je w dowolnej kolejności, ale chcę,
var
aby pojawił się w pierwszym bloku, w którymaction
jest używany, muszę dostosowaćcase
bloki odpowiednio.Gdyby to zmienić na to:
case BindingType.Inherited: var action = (byte)ChangeAction.Inherit; return (x => x.Action == action); case BindingType.ExplicitValue: action = (byte)ChangeAction.SetValue; goto case BindingType.Inherited;
Wtedy nie dostaję błędu, ale w pewnym sensie wygląda na to, że zmiennej przypisuje się wartość, zanim zostanie zadeklarowana.
(Chociaż nie mogę myśleć o żadnym momencie, w którym naprawdę chciałbyś to zrobić - nawet nie wiedziałem, żegoto case
istniał wcześniej)
Więc moje pytanie brzmi: dlaczego projektanci C # nie dali case
blokom własnego lokalnego zasięgu? Czy są tego jakieś historyczne lub techniczne powody?
switch
w ogóle - jestem ciekawy uzasadnienia tego projektu.
break
nie jest możliwy w C #.
action
zmienną przedswitch
instrukcją lub umieść każdy przypadek w osobnych nawiasach klamrowych, a uzyskasz rozsądne zachowanie.