Установить только для чтения поля в конструкторе локальной функции С#

Следующее не компилируется.

public class A
{
    private readonly int i;

    public A()
    {
        void SetI()
        {
            i = 10; 
        }

        SetI();
    }
}

Это терпит неудачу с этой ошибкой:

CS0191 Поле, доступное только для чтения, не может быть назначено (кроме как в конструкторе или инициализаторе переменной)

Технически мы все еще не в конструкторе, так как видимость локальной функции ограничена, поэтому мне интересно, почему это не компилируется.

Ответы

Ответ 1

Компилятор превращает локальную функцию SetI в отдельный метод уровня класса. Поскольку этот отдельный метод уровня класса не является конструктором, вы не можете назначать ему поля только для чтения.

Таким образом, компилятор принимает это:

public class A
{
    private readonly int i;

    public A()
    {
        void SetI()
        {
            i = 10; 
        }

        SetI();
    }
}

и превращает это в это:

public class A
{
    private readonly int i;

    public A()
    {
        <.ctor>g__SetI|1_0();
    }

    [CompilerGenerated]
    private void <.ctor>g__SetI|1_0()
    {
        i = 10;
    }
}

(SharpLab. Я остановил readonly чтобы он скомпилировался.)

Как видите, он пытается присвоить i из метода <.ctor>g__SetI|1_0(), который не является конструктором.

К сожалению, спецификация языка С# 7.0 еще не опубликована, поэтому я не могу ее процитировать.

Точно так же происходит, если вы попытаетесь использовать делегата:

public class A
{
    private readonly int i;

    public A()
    {
        Action setI = () => i = 10;

        setI();
    }
}

Компилируется в:

public class A
{
    private readonly int i;

    public A()
    {
        Action action = <.ctor>b__1_0;
        action();
    }

    [CompilerGenerated]
    private void <.ctor>b__1_0()
    {
        i = 10;
    }
}

(SharpLab, снова без readonly.)

... который также не компилируется.