如何确定 .NET (BCL) 类型是否不可变
本文关键字:类型 是否 不可变 BCL 何确定 NET | 更新日期: 2023-09-27 18:34:15
从这个答案中,我开始知道KeyValuePair是不可变的。
我浏览了文档,但找不到有关不可变行为的任何信息。
我想知道如何确定类型是否不可变?
我认为没有标准的方法可以做到这一点,因为 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()
对突变前的值进行操作。
所有非平凡结构,无论它们是如何声明的,其字段都有相同的不可变性规则:可以更改结构的代码可以更改其字段;不能更改结构的代码不能更改其字段。 一些结构可能会迫使人们通过箍来更改他们的一个字段,但是将结构类型设计为"不可变"既没有必要也不足以确保实例的不可变性。 "不可变"结构类型有一些合理的用法,但是这样的用例需要比具有公开公共字段的结构更小心。