如何实例化一个大的不可变类型?

时间:2010-06-24 20:38:57

标签: c# immutability instantiation

我有一个包含大约40个属性(所有值类型)的类型,它代表我的业务的一种交易。此类的实例对应于我的数据库中的一行。我想保持我的类不可变,因为它只会用于读取操作,但我不知道如何在初始化期间设置40个属性。

通常我对不可变类型使用构造函数初始化,但我想避免编写带有40个参数的构造函数。我的房产的安装人员目前是私人的,但我愿意以足够的理由改变。是否有一种常见的方法来处理这种情况或更好的方法来解决问题?

6 个答案:

答案 0 :(得分:10)

你的问题不是一个有40个参数的构造函数,而是一个有40个字段的类。

我建议打破这个。是否有任何相关领域?如果是这样,将它们分组到一个公共对象(例如EmailInfo),然后让你的大对象引用分组对象。

// Instead of this:
foo.EmailHeader
foo.EmailSubject
foo.Email...

// Do this:
foo.Email.Header
foo.Email.Subject

一旦你的类具有较少的直接属性,创建一个获取那些分组对象的构造函数并不是那么糟糕。

答案 1 :(得分:8)

快点。你提到你对象的setter是私有的。如果是这种情况,那么您的对象不是不可变的(否则setter不存在)。最好你的对象是只读的。

对于一个真正的不可变对象,别无选择,只能让构造函数接受初始化对象所需的所有值。减少构造函数中参数数量的最佳方法是将值分组为更大的对象,然后将这些对象传递给构造函数。虽然我不会这样做,除非这些值在逻辑上是相关的。

如果你的不可变类型确实需要40个值而且它们不相关,那么最好的方法是使用40个值的构造函数。那还是进一步打破了大不可变对象。

答案 2 :(得分:4)

我喜欢使用可变对象来实例化不可变对象的方法;可变对象只是为了整理选项。 .NET框架中的一个例子是ProcessStartInfo

class XInfo {
  public int A;
  public int B;
}

class X {
  public X (XInfo i) {
    // you can transform the data/layout from i any way you need
    ..
  }
}

new X(new XInfo() {
  A = 42
})

虽然我会对'40个属性'保持不变,但我发现上述方法效果很好。额外的好处是XInfoX中使用的内部结构可能完全不同,只要您能提供合理的映射。

答案 3 :(得分:1)

如果我按照你的说法“但我不确定如何在初始化期间设置40个属性。”,您的问题似乎是一个具有太多字段/属性的类。 似乎不是让它变成不可变的问题,因为你已经知道如何做到这一点。

我建议(和其他人一样),Refactor和Extract Class。

答案 4 :(得分:0)

作为替代方案,您可以使您的课程来自freezable,我认为这可能是您要搜索的解决方案。您可以对对象进行Instatiate,设置值,然后将其设置为冻结。一旦你将它设置为冻结,该类就是“只读”。

答案 5 :(得分:0)

我建议将参数放入一个或多个结构中,并让对象保存这些结构。嵌套对象是可能的,但会比嵌套结构增加更多的开销。

作为替代方案,您可以使用所有属性的“readonly mustoverride”版本创建一个抽象基类。由此,派生出一个可变且不可变的对象类。不可变的可以在其构造函数中接受基类,并使用所有readonly属性来构建新对象。可变类可以提供一种使用方法编写属性的方法,使用不同名称的读写属性来读取只读版本等。