本文介绍了有没有简单的方法来制作类的不可变版本?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

有没有简单的方法可以使实例不可变?

Is there an easy way to make an instance immutable?

让我们举一个例子,我有一个类,其中包含很多数据字段(仅数据,无行为) ):

Let's do an example, I have a class holding a lots of data fields (only data, no behavior):

class MyObject
{
    // lots of fields painful to initialize all at once
    // so we make fields mutable :

    public String Title { get; set; }
    public String Author { get; set; }

    // ...
}

示例创建:

MyObject CreationExample(String someParameters)
{
    var obj = new MyObject
    {
        Title = "foo"
        // lots of fields initialization
    };

    // even more fields initialization
    obj.Author = "bar";

    return obj;
}

但是现在我已经完全创建了对象,所以我不想对象变得不再可变(因为数据使用者永远不需要更改状态),所以我想要这样的内容:

But now that I have fully created my object, I don't want the object to be mutable anymore (because the data consumer will never need to change the state), so I would like something like that List.AsReadOnly:

var immutableObj = obj.AsReadOnly();

但是如果我想要这种行为,我需要制作另一个具有完全相同字段但没有设置器。

But if I want this behavior, I need to make another class that have exactly the same fields but without setter.

那么有没有自动的方法来生成这个不可变的类?或者另一种允许创建过程中具有可变性但一旦初始化就不可变的方法?

So is there any automatic way to generate this immutable class ? Or another way to allow mutability during creation but immutable once initialized ?

我知道字段可以标记为只读,但是对象将在类外部进行初始化,并且将所有字段作为构造函数参数传递似乎是一个坏主意(太多参数)。

I know that fields can be marked as "readonly", but the object will be initialized outside of the class, and passing all fields as constructor parameters seems like a bad idea (too much parameters).

推荐答案

不,这并不容易使任何类型不可变的方法,特别是如果您希望深度不可变(即,通过不可变对象无法到达可变对象)时,则不应该这样做。您将必须明确将类型设计为不可变的。使类型不可变的常用机制如下:

No, there is no easy way to make any type immutable, especially not if you want "deep" immutability (i.e. where no mutable object can be reached through the immutable object). You will have to explicitly design your types to be immutable. The usual mechanisms to make types immutable are these:


  • 声明(属性支持)字段只读。 (或者,从C#6 / Visual Studio 2015开始,使用。)

  • 不公开属性设置器,只公开获取器。

  • Declare (property-backing) fields readonly. (Or, starting with C# 6 / Visual Studio 2015, use read-only auto-implemented properties.)
  • Don't expose property setters, only getters.

要初始化(支持属性)字段,必须在构造函数中对其进行初始化。因此,请将(属性)值传递给构造函数。

In order to initialize (property-backing) fields, you must initialize them in the constructor. Therefore, pass the (property) values to the constructor.

不要公开可变对象,例如基于默认可变类型的集合(例如 T [] List< T> Dictionary< TKey,TValue> 等。)

Don't expose mutable objects, such as collections based on mutable-by-default types (like T[], List<T>, Dictionary<TKey,TValue>, etc.).

如果需要公开集合,请在防止修改的包装器中返回它们(例如, .AsReadOnly ()),或至少返回内部集合的新副本。

If you need to expose collections, either return them in a wrapper that prevents modification (e.g. .AsReadOnly()), or at the very least return a fresh copy of the internal collection.

使用Builder模式。以下示例过于琐碎,无法做到模式正确,因为通常建议在需要创建非平凡对象图的情况下使用它;尽管如此,基本思想还是这样:

Use the Builder pattern. The following example is too trivial to do the pattern justice, because it's usually recommended in cases where non-trivial object graphs need to be created; nevertheless, the basic idea is something like this:

class FooBuilder // mutable version used to prepare immutable objects
{
    public int X { get; set; }
    public List<string> Ys { get; set; }
    public Foo Build()
    {
        return new Foo(x, ys);
    }
}

class Foo // immutable version
{
    public Foo(int x, List<string> ys)
    {
        this.x = x;
        this.ys = new List<string>(ys); // create a copy, don't use the original
    }                                   // since that is beyond our control
    private readonly int x;
    private readonly List<string> ys;
    …
}


这篇关于有没有简单的方法来制作类的不可变版本?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-16 07:41