【问题标题】:Constructor for class with readonly field of immutable storage具有不可变存储的只读字段的类的构造函数
【发布时间】:2019-03-14 02:11:32
【问题描述】:

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

class Abc
{
    readonly ImmutableList<int> elts;

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

鉴于所示的构造函数,很容易从一些ints 创建一个实例:

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

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

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)

可能看起来它正在创建一个带有单个元素 (item) 的 Abc。但是如果item实际上是一个具有多个项目的IEnumerable&lt;int&gt;,则会调用上面的第二个构造函数。

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

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

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

    ...
}

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

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

【问题讨论】:

  • 让它调用一个(私有的?)构造函数。
  • @SLaks 感谢您的建议!看起来约翰根据您的建议提供了答案。看起来不错!
  • 如果elts 已经是私有的,为什么还要将它设为只读?
  • @shingo 如果不出意外,这是告诉未来的维护者即使 Abc 类中的代码也不应该在构造类之后替换 elts 的好方法。

标签: c# immutable-collections


【解决方案1】:

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

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

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

试试这个:

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

【讨论】:

    【解决方案2】:

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

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

    如果您没有任何公共构造函数,那么创建Abc 实例的唯一方法(无需反射)是使用静态方法。

    【讨论】:

    • 谢谢约翰!这就说得通了。我可能会采用这种方法。
    • @dharmatech 我建议接受 Strom 的回答,因为它首先出现,基本相同,而且更详细:)
    猜你喜欢
    • 1970-01-01
    • 2011-12-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多