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

本文关键字:类型 是否 不可变 BCL 何确定 NET | 更新日期: 2023-09-27 18:34:15

从这个答案中,我开始知道KeyValuePair是不可变的。

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

我想知道如何确定类型是否不可变?

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

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

1( 该类型的所有属性都有一个专用set

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

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

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

ImmutabeAttribute这样的东西会很好。这里有一些想法(在评论中的某个地方(,但我还没有在"现实生活"中看到过。

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

"此属性是只读的。">

我认为仅通过查看文档无法找到不变性的"证明",但有几个强有力的指标:

  • 这是一个struct(为什么这很重要?
  • 它没有可设置的公共属性(两者都是只读的(
  • 它没有明显的突变体方法

为了获得明确的证据,我建议从Microsoft下载 BCL 的引用源,或使用 IL 反编译器向你展示类型在代码中的外观。

KeyValuePair<T1,T2>是一个结构,如果没有反射,它只能通过复制另一个保存所需值的KeyValuePair<T1,T2>的内容来在其构造函数之外发生突变。 请注意,该语句:

 MyKeyValuePair = new KeyValuePair(1,2(;

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

请考虑以下代码:

静态键值对 MyKeyValuePair; 某些类中的字段线程1  MyKeyValuePair = new KeyValuePair(1,1(; //***  MyKeyValuePair = new KeyValuePair(2,2(;线程2  st = MyKeyValuePair.ToString((;

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

所有非平凡结构,无论它们是如何声明的,其字段都有相同的不可变性规则:可以更改结构的代码可以更改其字段;不能更改结构的代码不能更改其字段。 一些结构可能会迫使人们通过箍来更改他们的一个字段,但是将结构类型设计为"不可变"既没有必要也不足以确保实例的不可变性。 "不可变"结构类型有一些合理的用法,但是这样的用例需要比具有公开公共字段的结构更小心。