Почему этот код работает? Я использую C# 8 с Visual Studio 2019.
Вы ответили на свой вопрос! Это потому, что вы используете C# 8.
Правило от C# 1 до 7 гласило: простое имя нельзя использовать для обозначения двух разных вещей в одной локальной области. (Действительное правило было несколько сложнее, но описывало, как это утомительно; подробности см. В спецификации C#.)
Цель этого правила состояла в том, чтобы предотвратить ситуацию, о которой вы говорите в вашем примере, где становится очень легко запутаться в значении местного. В частности, это правило было разработано для предотвращения таких недоразумений, как:
class C
{
int x;
void M()
{
x = 123;
if (whatever)
{
int x = 356;
...
И теперь у нас есть ситуация, когда внутри тела M
, x
означает как this.x
, так и локальное x
.
Несмотря на благие намерения, с этим правилом возникло несколько проблем:
- Оно не было реализовано до c. Были ситуации, когда простое имя могло использоваться как, скажем, как тип, так и свойство, но они не всегда были помечены как ошибки, поскольку логика обнаружения ошибок c была ошибочной. (См. Ниже)
- Сообщения об ошибках были сбиты с толку и содержали непоследовательные сообщения. Для этой ситуации было несколько разных сообщений об ошибках. Они непоследовательно опознали преступника; то есть иногда вызывается использование inner , иногда external , а иногда это просто сбивает с толку.
Я попытался переписать Рослин, чтобы разобраться в этом; Я добавил несколько новых сообщений об ошибках и сделал старые согласованными относительно того, где сообщалось об ошибке. Однако, это усилие было слишком мало, слишком поздно.
Команда 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/
В конце третьей части я заметил, что между этой функцией и функцией «Цветовой цвет» также было взаимодействие - то есть функция, которая позволяет:
class C
{
Color Color { get; set; }
void M()
{
Color = Color.Red;
}
}
Здесь мы использовали простое имя Color
для обозначения как this.Color
, так и перечислимого типа Color
; в соответствии со строгим прочтением спецификации, это должно быть ошибкой, но в этом случае spe c был неправильным, и намерение было разрешить это, так как этот код однозначен, и было бы неприятно заставить разработчика изменить его.
Я никогда не писал эту статью, описывающую все странные взаимодействия между этими двумя правилами, и сейчас было бы немного бессмысленно делать это!