Я писав цей код:
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.");
}
}
І був здивований, виявивши помилку компіляції:
Локальна змінна назва "дія" вже визначена в цій області
Вирішити це було досить просто; просто позбувшись другого var
зробив трюк.
Очевидно, що змінні, задекларовані в case
блоках, мають сферу використання батьків switch
, але мені цікаво, чому це так. З огляду на , що C # не дозволяє виконання провалитися інших випадках (це вимагає break
, return
, throw
або goto case
заяви в кінці кожного case
блоку), здається , досить дивно , що це дозволило б оголошення змінних в один , case
щоб використовувати або конфлікт зі змінними в будь-який інший case
. Іншими словами, здається, що змінні потрапляють через case
оператори, хоча виконання не може. C # докладає великих зусиль для підвищення читабельності, забороняючи деякі конструкції інших мов, які плутають або легко зловживають. Але це здається, що це просто зобов'язане викликати плутанину. Розглянемо наступні сценарії:
Якби змінити це на це:
case BindingType.Inherited: var action = (byte)ChangeAction.Inherit; return (x => x.Action == action); case BindingType.ExplicitValue: return (x => x.Action == action);
Я отримую " Використання непризначеної локальної змінної" дії " ". Це заплутано, тому що в будь-якій іншій конструкції в C #, про яку я можу подумати
var action = ...
, ініціалізувала б змінну, але тут вона просто оголошує її.Якби я міняв місцями такі випадки:
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);
Я отримую " Неможливо використовувати локальну змінну" дія "до того, як вона буде оголошена ". Отже, порядок блоків регістрів тут є важливим таким чином, що не зовсім очевидно - зазвичай я можу писати їх у будь-якому бажаному порядку, але тому, що
var
обов'язково з'являється в першому блоці, деaction
він використовується, я повинен налаштуватиcase
блоки відповідно.Якби змінити це на це:
case BindingType.Inherited: var action = (byte)ChangeAction.Inherit; return (x => x.Action == action); case BindingType.ExplicitValue: action = (byte)ChangeAction.SetValue; goto case BindingType.Inherited;
Тоді я не отримую помилок, але в певному сенсі схоже на те, що змінній призначається значення перед тим, як її оголосити.
(Хоча я не можу припустити, коли б ви насправді хотіли це зробити - я навіть не знав, щоgoto case
існував раніше)
Отже, моє запитання: чому дизайнери C # не дали case
блокам власну локальну область застосування? Чи є якісь історичні чи технічні причини для цього?
switch
зовсім - мені просто цікаво міркувати за цим дизайном.
break
не можлива в C #.
action
змінну передswitch
твердженням або поставте кожен випадок у власні дужки, і ви отримаєте розумну поведінку.