是否可以创建不可变对象而不传递构造函数中的所有内容?

jav*_*red 6 c#

我想让我的课堂不变.显而易见的方法是将所有字段声明为get; private set;并初始化构造函数中的所有字段.所以客户必须在构造函数中提供所有内容 问题是,当构造函数中有大约10个或更多字段传递它们变得非常难以理解时,因为每个字段都没有标签.

例如,这很可读:

info = new StockInfo
        {
            Name = data[0] as string,
            Status = s,
            LotSize = (int)data[1],
            ISIN = data[2] as string,
            MinStep = (decimal)data[3]
        };
Run Code Online (Sandbox Code Playgroud)

与此相比:

new StockInfo(data[0] as string, s, (int) data[1], data[2] as string, (decimal) data[3])
Run Code Online (Sandbox Code Playgroud)

现在成像我有10个或更多参数.

那么如何才能使类不可变保存可读性?

我建议只在使用构造函数时使用相同的格式:

info = new StockInfo(
            data[0] as string,           // Name
            s,                           // Status
            (int)data[1],                // LotSize
            data[2] as string,           // ISIN
            (decimal)data[3]             // MinStep
       );
Run Code Online (Sandbox Code Playgroud)

你能提出更好的建议吗?

Ada*_*dam 8

以下是使用C#命名参数的方法:

var info = new StockInfo
(
    Name: data[0] as string,
    Status: s,
    LotSize: (int)data[1],
    ISIN: data[2] as string,
    MinStep: (decimal)data[3]
);
Run Code Online (Sandbox Code Playgroud)

  • @Mark我认为如果你完全阅读这个问题并不是真的相关(我知道,标题*确实*要求解决方案而不传递构造函数中的所有内容).OP非常清楚他的问题*真的*是`那么我怎么能让类不可变的保存可读性呢?`我认为我的代码片段应该提供一个很好的例子来配合Maciek的优秀答案. (2认同)

Ani*_*Ani 7

这里有一些选择.你必须决定什么是最适合你的:

使用带有命名参数的经典不可变对象(带有大量构造函数)以提高可读性.(缺点:有些人不赞成使用许多构造函数参数.如果不支持命名参数,可能不方便使用其他.NET语言.)

info = new StockInfo
           (
             name: data[0] as string,
             status: s,
             ...
           )
Run Code Online (Sandbox Code Playgroud)

通过不可变接口公开可变对象.(缺点:对象仍然可以通过强制转换进行变异.要写入额外的类型.)

public interface IStockInfo
{
   string Name { get; }
   string Status { get; }
}

IStockInfo info = new StockInfo
                      {
                          Name = data[0] as string,
                          Status = s,
                          ...
                      }
Run Code Online (Sandbox Code Playgroud)

公开可变对象的只读视图 - ReadOnlyCollection<T>例如,参见.(缺点:实现额外的类型.创建额外的对象.额外的间接.)

var readOnlyInfo = new ReadOnlyStockInfoDecorator(info);
Run Code Online (Sandbox Code Playgroud)

公开可变对象的不可变克隆.(缺点:要实现的额外类型.创建了额外的对象.需要复制.)

var immutableInfo = new ImmutableStockInfo(info);
Run Code Online (Sandbox Code Playgroud)

使用freezable对象.(缺点:冻结后突变 - 尝试在执行时才会被捕获.)

info.Freeze();
info.Name = "Test"; // Make this throw an exception.
Run Code Online (Sandbox Code Playgroud)

使用流畅式的构建器或类似的(缺点:有些人可能不熟悉模式.需要编写大量额外代码.创建了大量副本.中间状态可能是非法的)

info = StockInfo.FromName(data[0] as string)
                .WithStatus(s) // Make this create a modified copy
                .WithXXX() ;
Run Code Online (Sandbox Code Playgroud)


Mac*_*ska 6

不,这是不可能的.你有不可变对象或者你想要有能力修改对象.

  1. 您可以使用命名参数.
  2. 您可以考虑传递其他对象(和组参数),以便一个对象仅包含某些非常相似的参数.

看看你的代码我也建议你首先提取参数,所以不要传递像data[0] as string你一样使用string stockName = data[0] as string;然后使用的东西stockName.这应该使您的代码更具可读性.

如果您将如此多的参数传递给对象的构造函数,那么修改您的设计可能是个好主意.您可能违反了单一责任原则.