如何确定.NET(BCL)类型是否是不可变的

时间:2012-05-14 09:00:49

标签: c# .net immutability

Answer开始,我发现KeyValuePair是不可变的。

我浏览了docs,但无法找到有关不可变行为的任何信息。

我想知道如何判断一个类型是否是不可变的?

4 个答案:

答案 0 :(得分:1)

我认为没有一种标准的方法可以做到这一点,因为C#中没有关于不变性的官方概念。我能想到的唯一方法是查看某些事情,表明概率更高:

1)该类型的所有属性都具有私有set

2)所有字段均为const / readonly或私有

3)没有明显/已知副作用的方法

4)另外,作为一个结构通常是一个很好的指示(如果它是BCL类型或由有此指导的人)

ImmutabeAttribute这样的东西会很好。有一些想法here(在评论的某处),但我还没有在“现实生活”中看到过。

答案 1 :(得分:0)

第一个迹象是概述中属性的文档说“获取键/值对中的键”。 第二个更明确的指示是在财产本身的描述中:

"This property is read/only."

答案 2 :(得分:0)

我认为只要查看文档就不能找到不可变性的“证据”,但有几个强有力的指标:

  • 这是structwhy does this matter?
  • 它没有可设置的公共属性(两者都是只读的)
  • 没有明显的变异方法

为了明确证明,我建议从Microsoft下载BCL的reference source或使用IL反编译器向您展示代码中的类型。

答案 3 :(得分:0)

KeyValuePair<T1,T2>是一个结构,在没有Reflection的情况下,只能通过复制保存所需值的另一个KeyValuePair<T1,T2>的内容在其构造函数之外进行变异。请注意声明:

  MyKeyValuePair = new KeyValuePair(1,2);

就像结构上所有类似的构造函数调用一样,实际上是通过创建KeyValuePair<int,int>的新临时实例(在构造函数本身执行之前发生),设置该实例的字段值(由构造函数完成),复制所有该新临时实例的公共和私有字段为MyKeyValuePair,然后丢弃临时实例。

请考虑以下代码:

static KeyValuePair MyKeyValuePair;  // Field in some class

// Thread1
  MyKeyValuePair = new KeyValuePair(1,1);
  // ***
  MyKeyValuePair = new KeyValuePair(2,2);

// Thread2
  st = MyKeyValuePair.ToString();

因为MyKeyValuePair的长度恰好是四个字节,所以Thread1中的第二个语句将同时更新这两个字段。尽管如此,如果Thread1中的第二个语句在Thread2对MyKeyValuePair.Key.ToString()MyKeyValuePair.Value.ToString()的评估之间执行,则第二个ToString()将对结构的新变异值起作用,即使第一个已经 - 已完成ToString()根据突变前的值进行操作。

所有非平凡的结构,无论它们如何被声明,都对其字段具有相同的不变性规则:可以更改结构的代码可以更改其字段;无法更改结构的代码无法更改其字段。一些结构可能会迫使一个人通过环来改变他们的一个领域,但设计结构类型是“不可变的”既不必要也不足以确保实例的不变性。 “不可变”结构类型有一些合理的用法,但是如果有任何需要比使用暴露公共字段的结构所需要更多的注意事项,则会出现这种情况。