不变性的真正定义?

我想知道如何定义不变性? 如果值没有公开,那么无法修改,那就够了吗?

是否可以在类型内修改值,而不是类型的客户?

或者只能将它们设置在构造函数中? 如果是这样,在双初始化的情况下(在结构上使用this关键字等)对于不可变类型仍然可以吗?

我怎样才能保证该类型是100%不可变的?

如果值没有公开,那么无法修改,那就够了吗?

不,因为您需要读取权限。

是否可以在类型内修改值,而不是类型的客户?

不,因为那仍然是突变。

或者只能将它们设置在构造函数中?

丁丁丁! 另外一点,不可变类型通常具有构造和返回新实例的方法,并且通常还有额外的构造函数标记为internal专门供这些方法使用。

我怎样才能保证该类型是100%不可变的?

在.Net中获得这样的保证是很棘手的,因为你可以使用reflection来修改(变异)私有成员。

之前的海报已经说明你应该在构造函数中为你的字段赋值,然后把它们放在手上。 但这有时说起来容易做起来难。 假设您的不可变对象公开了List类型的属性。 该列表是否允许更改? 如果没有,你将如何控制它?

Eric Lippert在他的博客中写了一系列关于C#不变性的post,你可能会感兴趣: 你在这里找到了第一部分 。

我认为在所有这些答案中可能会遗漏的一件事是,我认为即使内部状态发生变化,对象也可以被认为是不可变的 – 只要这些内部变更对’客户’代码不可见。

例如, System.String类是不可变的,但我认为允许缓存实例的哈希代码,因此哈希仅在第一次调用GetHashCode() 。 请注意,据我所知, System.String类不会这样做,但我认为它可以并且仍然被认为是不可变的。 当然,任何这些更改都必须以线程安全的方式处理(与更改的不可观察方面一致)。

说实话,我想不出有很多可能需要或者需要这种“看不见的可变性”的理由。

以下是维基百科的不变性定义( 链接 )

“在面向对象和函数式编程中,不可变对象是一个对象,其状态在创建后无法修改。”

基本上,一旦创建了对象,就不能改变它的任何属性。 一个例子是String类。 创建String对象后,无法更改。 对它执行的任何操作实际上都会创建一个新的String对象。

那里有很多问题。 我会尝试单独回答每个问题:

  • “我想知道如何定义不变性?” – 直接来自维基百科页面 (以及完全准确/简洁的定义)

    不可变对象是一个对象,其状态在创建后无法修改

  • “如果价值不是公开的,那么不能修改,那就足够了?” – 不完全的。 它无法以任何方式进行修改,因此您必须确保方法/函数不会更改对象的状态,并且如果执行操作,则始终返回新实例。

  • “可以在类型内修改值,而不是类型的客户吗?” – 从技术上讲,它不能在内部或由类型的消费者修改。 在实践中,存在类型如System.String (该事项的引用类型),几乎所有实际目的都可以认为是可变的,尽管不是理论上的。

  • “或者只能将它们设置在构造函数中?” – 是的,理论上这是唯一可以设置状态(变量)的地方。

  • “如果是这样,在双重初始化的情况下(在结构上使用this关键字等)对于不可变类型仍然可以吗?” – 是的,这仍然完全正常,因为它是初始化(创建)过程的所有部分,并且实例在完成之前不会返回。

  • “我如何保证该类型是100%不可变的?” – 以下条件应该确保。 (有人请指出,如果我错过了一个。)

    1. 不要暴露任何变量。 它们都应该保密(甚至protected也是可以接受的,因为派生类可以修改状态)。
    2. 不允许任何实例方法修改状态(变量)。 这应该只在构造函数中完成,而方法应该使用特定的构造函数创建新实例,如果它们需要返回“已修改”的对象。
    3. 暴露(作为只读)或方法返回的对象的所有成员本身必须是不可变的。

    注意:您无法确保派生类型的不变性,因为它们可以定义新变量。 这是标记任何类型的原因,你不能确保它是不可变的sealed这样在代码中的任何地方都不能认为派生类是你的基本不可变类型。

希望有所帮助。

我已经了解到,不可变性是指在构造函数中设置所有内容并且在对象的生命周期内不能稍后修改它。

不变性的定义可以在Google上找到 。

例:

不可变的 – 字面意思是,无法改变。
http://www.filosofia.net/materiales/rec/glosaen.htm

就不可变数据结构而言,典型定义是一次写入多次读取,换句话说,正如您所说,一旦创建,它就无法更改。

有些情况略微处于灰色区域。 例如,.NET字符串被认为是不可变的,因为它们无法更改,但是,StringBuilder在内部修改了String对象。

不可变的本质上是一个强迫自己在自己的代码中成为最终的类。 一旦它在那里,什么都不能改变。 据我所知,事情是在构造函数中设置的,然后就是这样。 我不知道其他东西怎么可能是不可变的。

不幸的是,在c#/ vb.net中没有不可变的关键字,虽然它已被争论,但是如果没有autoproperties并且所有字段都用readonly声明(readonly字段只能在构造函数中分配)modfier并且所有字段都被声明为一个不可改变的类型,你将确保自己的不变性。

不可变对象是一种可观察状态永远不会被任何合理的代码执行序列改变的对象。 不可变类型是一种保证暴露给外部世界的任何实例都是不可变的类型(这个要求通常被声明为要求对象的状态只能在其构造函数中设置;对于具有对象的对象,这不是绝对必要的私有构造函数,对于在构造期间调用外部方法的对象也不够。

然而,其他答案忽略的一点是对象状态的定义。 如果Foo是一个类,则List的状态由其中包含的对象标识序列组成。 如果对特定List实例的唯一引用由代码保存,既不会导致更改该序列,也不会将其公开给可能执行此操作的代码,那么该实例将是不可变的,无论Foo对象是否引用其中是可变的或不可改变的。

使用类比,如果有一个汽车VIN列表(车辆识别号码)打印在防篡改纸上,列表本身将是不可变的,即使汽车不是。 即使列表今天包含十辆红色汽车,明天也可能包含十辆蓝色汽车; 然而,它们仍然是十辆汽车