class 的构造函数,具有不可变存储的只读字段

Constructor for class with readonly field of immutable storage

假设我们有以下简单的class。请注意,唯一的字段是 readonly 并且用于 ImmutableList<int>:

class Abc
{
    readonly ImmutableList<int> elts;

    public Abc(params int[] ls) => elts = ImmutableList.CreateRange(ls);
}

鉴于显示的构造函数,从 int 中创建实例非常容易:

var result_a = new Abc(10, 20, 30);

现在,我可能还想要一个可以在给定 IEnumerable<int>:

的情况下构建 Abc 的构造函数
public Abc(IEnumerable<int> ls) => elts = ImmutableList.CreateRange(ls);

所以我们的 class 现在看起来像这样:

class Abc
{
    readonly ImmutableList<int> elts;

    public Abc(params int[] ls) => elts = ImmutableList.CreateRange(ls);

    public Abc(IEnumerable<int> ls) => elts = ImmutableList.CreateRange(ls);
}

这确实有效:

var ls = new[] { 10, 20, 30 };

var result_b = new Abc(ls);

然而,这个构造函数有点笨拙,因为乍一看,是这样的:

new Abc(item)

可能看起来像是在用单个元素 (item) 创建 Abc。但是,如果 item 实际上是一个包含多个项目的 IEnumerable<int>,则将调用上面的第二个构造函数。

如果你看一下 Microsoft ImmutableList API,他们实际上有一个名为 ImmutableList.CreateRange 的静态方法,类似于上面的第二个构造函数。这很好,因为我们避免了上述视觉歧义。

好的,让我们开始为我们的 Abc class:

草拟一个类似构造函数的简单实现
public static Abc CreateRange(IEnumerable<int> ls)
{
    elts = ImmutableList.CreateRange(ls);

    ...
}

当然,我们运行在这里遇到了一个问题,因为elts字段是readonly并且不能通过这个静态方法初始化:

那么,为我们的 Abc class 实施 CreateRange 的好方法是什么?

设置 elts 的唯一方法是调用 Abc 的构造函数。

readonly 修饰符保证设置变量的唯一方法是在初始化期间,readonly int i=0; 或在构造函数中。

该错误是由于静态方法无法访问 Abc 的实例引起的,尽管您仍然无法修改它,因为它是 readonly.

试试这个:

public static Abc CreateRange(IEnumerable<int> ls)
{
   return new Abc(ls);
}

我相信 SLaks 的建议是创建一个私有构造函数并从静态方法中调用它:

private Abc(IEnumerable<int> ls) => elts = ImmutableList.CreateRange(ls);

public static Abc CreateRange(IEnumerable<int> ls) => new Abc(ls);

创建 Abc 实例的唯一方法(无需反射)是使用静态方法,假设您没有任何 public 构造函数。