c# - 有没有一种简单的方法来制作类的不可变版本?

标签 c# .net class immutability

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

举个例子,我有一个包含很多数据字段的类(只有数据,没有行为):

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;
}

但现在我已经完全创建了我的对象,我不希望对象再可变(因为数据消费者永远不需要更改状态),所以我想要类似的东西 List.AsReadOnly :

var immutableObj = obj.AsReadOnly();

但是如果我想要这种行为,我需要创建另一个具有完全相同的字段但没有 setter 的类。

那么有什么自动生成这个不可变类的方法吗?或者另一种在创建期间允许可变性但在初始化后不可变的方法?

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

最佳答案

不,没有简单的方法可以使任何类型不可变,尤其是如果您想要“深度”不变性(即无法通过不可变对象(immutable对象)访问可变对象)。您将必须明确地将您的类型设计为不可变的。使类型不可变的常用机制是:

  • 声明(属性支持)字段 readonly . (或者,从 C# 6/Visual Studio 2015 开始,使用 read-only auto-implemented properties 。)
  • 不要公开属性 setter,只公开 getter。

  • 为了初始化(属性支持)字段,您必须在构造函数中初始化它们。因此,将(属性)值传递给构造函数。

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

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

  • 使用构建器模式。下面的例子太简单了,不能很好地解释模式,因为通常建议在需要创建非平凡对象图的情况下使用它;尽管如此,基本思想是这样的:

    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;
        …
    }
    

关于c# - 有没有一种简单的方法来制作类的不可变版本?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26105608/

相关文章:

c# - 是一个字段,但像类型错误一样使用

c# - 在 ASP.NET Framework 3.5 中从 url 隐藏 .aspx

c# - Entity Framework 代码优先无法正常工作

.net - 如何修复 "No way to resolve conflict between"错误?

c# - 从 C# 中的命令获取 int 值

c# - 科学计数法中的 JSON.NET 整数

java - 如何基于字符串创建新类型的对象?

python - 如何在单个声明中创建多个空类?

c# - 使用反射为所有子类设置属性名称的值

java - 在java中不使用static的情况下在其他类中使用变量