Я писал этот код:
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.");
}
}
И был удивлен, обнаружив ошибку компиляции:
В этой области уже определена локальная переменная с именем 'action'
Это было довольно легко решить проблему; просто избавиться от второго 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);Я получаю « Не могу использовать локальную переменную« действие », прежде чем она объявлена ». Таким образом, порядок использования блоков case здесь важен не совсем очевидным образом. Обычно я могу записывать их в любом порядке, который мне нужен, но поскольку он
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вообще, не используя a - мне просто любопытно обосновать этот дизайн.
breakневозможна в C #.
actionпеременную передswitchоператором или поместите каждый случай в свои фигурные скобки, и вы получите разумное поведение.