Недавно я написал некоторый код, в котором непреднамеренно использовал имя переменной в качестве параметра действия, объявленного внутри функции, в которой уже есть переменная с тем же именем. Например:
var x = 1;
Action<int> myAction = (x) => { Console.WriteLine(x); };
Когда я обнаружил дублирование, я был удивлен, увидев, что код скомпилирован и работает отлично, чего нельзя ожидать от поведения, основанного на том, что я знаю о области видимости в C #. Некоторые быстро Googling оказалось так вопросы , которые жалуются , что подобный код действительно приводят к ошибке, например, лямбда - Scope разъяснения . (Я вставил этот пример кода в свою среду IDE, чтобы посмотреть, будет ли он работать, просто чтобы убедиться, что он работает отлично.) Кроме того, когда я вхожу в диалоговое окно «Переименование» в Visual Studio, первый из x
них выделяется как конфликт имен.
Почему этот код работает? Я использую C # 8 с Visual Studio 2019.
x
параметр этого метода выходит из области видимости. Смотрите sharplab для примера.Ответы:
Вы ответили на свой вопрос! Это потому, что вы используете C # 8.
Правило от C # 1 до 7 гласило: простое имя не может означать две разные вещи в одной локальной области. (Фактическое правило было немного более сложным, чем это, но описывало, как это утомительно; подробности см. В спецификации C #.)
Цель этого правила состояла в том, чтобы предотвратить ситуацию, о которой вы говорите в своем примере, когда очень легко запутаться в значении местного значения. В частности, это правило было разработано для предотвращения таких недоразумений, как:
И сейчас у нас возникла ситуация, когда внутри тела
M
,x
значит,this.x
и местноеx
.Несмотря на благие намерения, с этим правилом было несколько проблем:
Я попытался переписать Roslyn, чтобы разобраться в этом; Я добавил несколько новых сообщений об ошибках и сделал старые согласованными относительно того, где сообщалось об ошибке. Однако, это усилие было слишком мало, слишком поздно.
Команда C # решила для C # 8, что все правило вызывает больше путаницы, чем предотвращает, и это правило было удалено из языка. (Спасибо Джонатону Чейзу за определение, когда произошла отставка.)
Если вам интересно узнать историю этой проблемы и то, как я пытался ее исправить, посмотрите статьи, которые я написал об этом:
https://ericlippert.com/2009/11/02/simple-names-are-not-so-simple/
https://ericlippert.com/2009/11/05/simple-names-are-not-so-simple-part-two/
https://ericlippert.com/2014/09/25/confusing-errors-for-a-confusing-feature-part-one/
https://ericlippert.com/2014/09/29/confusing-errors-for-a-confusing-feature-part-two/
https://ericlippert.com/2014/10/03/confusing-errors-for-a-confusing-feature-part-three/
В конце третьей части я отметил, что между этой функцией и функцией «Цветовой цвет» также было взаимодействие, то есть функция, которая позволяет:
Здесь мы использовали простое имя
Color
для ссылки на оба типаthis.Color
и перечислимый типColor
; в соответствии со строгим прочтением спецификации, это должно быть ошибкой, но в этом случае спецификация была неправильной, и было намерение разрешить ее, поскольку этот код недвусмыслен, и было бы неприятно заставить разработчика изменить его.Я никогда не писал эту статью, описывающую все странные взаимодействия между этими двумя правилами, и сейчас было бы немного бессмысленно делать это!
источник