【问题标题】:Set readonly fields in a constructor local function c#在构造函数本地函数c#中设置只读字段
【发布时间】:2019-03-15 11:29:47
【问题描述】:

以下内容无法编译。

public class A
{
    private readonly int i;

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

        SetI();
    }
}

失败并出现此错误:

CS0191 无法将只读字段分配给(在构造函数或变量初始化程序中除外)

技术上我们还没有在构造函数中,因为本地函数的可见性是有限的,所以我想知道为什么它不能编译。

【问题讨论】:

  • 如果你能做到这一点,那么这个变量就不能再被称为只读了。根据定义,它只能在构造期间或使用初始化器设置一次。
  • 可能本地方法可以使用反射调用,这可能允许在构造后修改只读字段,所以这就是他们禁止它的原因..?
  • 如果您确实想要这样做,有两个明显的解决方法,顺便说一句:或者让SetI 返回所需的值而不是直接分配它,或者使用out 参数。当然,两者都涉及在构造函数本身中进行实际分配。因为本地函数被记录为私有方法,只是具有不同的范围规则,这有点一致。如果不对运行时进行(相当令人讨厌的)更改以建立调用者的“只读路径”,C# 在技术上是不可能支持这一点的——这并不值得。
  • 我认为构造函数可以直接将readonly 字段作为refout 参数传递,从而允许接收它的函数执行存储到该字段(您描述它的方式听起来好像构造函数必须传递一个临时值,然后将其复制到 readonly 字段本身)。

标签: c# constructor compiler-errors readonly local-functions


【解决方案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,所以它会编译。)

如您所见,它试图从方法 &lt;.ctor&gt;g__SetI|1_0() 分配 i,这不是构造函数。

很遗憾,C# 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。)

...同样无法编译。

【讨论】:

  • 感谢@canton7,我期待c#7/8 语言规范何时/如果它到来。
猜你喜欢
  • 1970-01-01
  • 2014-11-03
  • 1970-01-01
  • 2019-12-13
  • 1970-01-01
  • 1970-01-01
  • 2013-08-08
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多