在C#中,值类型是可变的还是不可变的?
值类型行为表明,我们持有的任何值都无法通过其他变量进行更改。
但是我仍然对我在这篇文章的标题中提到的内容感到困惑。 任何人都可以澄清吗?
值类型可以是可变的( 或模数一些奇怪的边缘情况)不可变,具体取决于您如何编写它们。
易变的:
public struct MutableValueType { public int MyInt { get; set; } }
一成不变的:
public struct ImmutableValueType { private readonly int myInt; public ImmutableValueType(int i) { this.myInt = i; } public int MyInt { get { return this.myInt; } } }
内置值类型( int
, double
等) 是不可变的,但您可以非常轻松地创建自己的可变struct
。
一条建议: 不要 。 可变值类型是一个坏主意,应该避免。 例如,这段代码的作用是什么:
SomeType t = new SomeType(); tX = 5; SomeType u = t; tX = 10; Console.WriteLine(uX);
这取决于 。 如果SomeType
是值类型,则打印5
,这是一个非常令人困惑的结果。
有关为何应避免使用可变值类型的详细信息,请参阅此问题 。
所有原始值类型,如int,double,float都是不可变的。但是结构本身是可变的。所以你必须采取措施使它们成为不可变的,因为它可以产生很多混淆。
保存任何信息的任何值类型实例都可以通过代码进行变异,该代码可以写入包含它的存储位置,并且没有值类型实例可以被不能写入包含它的存储位置的代码变更。 这些特性使得可变值类型的私有存储位置在许多场景中成为理想的数据容器,因为它们将来自可变性的更新便利性与来自不变性的控制相结合。 请注意,可以编写值类型的代码,使得在没有首先包含包含所需数据的实例(可能是新创建的临时实例)并且覆盖内容的情况下,不可能改变现有实例。前一个实例具有后者的内容,但这不会使值类型变得比它没有这样的能力更多或更少可变。 在许多情况下,它只会使变异变得尴尬,并使其看起来像一个如下声明:
MyKeyValuePair = new KeyValuePair(MyKeyValuePair.Key + 1,MyKeyValuePair.Value + 1>;
将创建一个新实例,但不会影响现有实例。 如果KeyValuePair
是一个不可变类,并且一个线程正在执行MyKeyValuePair.ToString()
而另一个线程正在执行上述代码,则ToString
调用将对旧实例或新实例执行操作,从而产生旧值或两者都产生新的价值观。 但是,因为KeyValuePair
是一个结构,上面的语句将创建一个新实例,但它不会使MyKeyValuePair
引用新实例 – 它只会将新实例用作模板,其字段将被复制到MyKeyValuePair
。 如果KeyValuePair
是一个可变结构,那么上述代码可能意图含义的最自然表达式更像是:
MyKeyValuePair.Key + = 1; MyKeyValuePair.Value + = 1;
也许:
var temp = MyKeyValuePair; MyKeyValuePair.Key = temp.Key + 1; MyKeyValuePair.Value = temp.Value + 1;
并且线程的含义会更加清晰。