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

时间:2019-03-14 02:11:32

标签: c# immutable-collections

假设我们有以下简单的类。请注意,唯一字段是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);

现在,我可能还想要一个可以在给定Abc的情况下构建IEnumerable<int>的构造函数:

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

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

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)

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

如果您查看Microsoft ImmutableList API,它们实际上具有称为ImmutableList.CreateRange的静态方法,该方法类似于上面的第二个构造函数。很好,因为我们避免了上述视觉上的歧义。

好的,让我们开始为Abc类草绘一个类似的构造函数的简单实现:

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

    ...
}

当然,我们在这里遇到问题,因为elts字段是readonly,并且无法通过此静态方法初始化:

enter image description here

那么,为我们的CreateRange类实现Abc的一种好方法是什么?

2 个答案:

答案 0 :(得分:2)

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

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

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

尝试以下方法:

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

答案 1 :(得分:1)

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

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

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

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