我最近开始阅读 C# 中的可变和不可变对象,我发现无论我在哪里读到的不变的东西是帽子是不可变的,这使得当用作哈希表中的键时线程安全且有用,但我不明白就概念而言虽然我们无法更改内容,但我们可以更改参考:
string s = "Hi";
s = "Bye";
虽然这里 s 的引用更改为“Bye”,但主要是 s 的内容(或者更确切地说它指向的内容)已经改变,并且从编程的角度来看是相同的,那么这是怎么回事如果字符串更改,则使特定函数线程安全或在哈希表中可用??
我最近开始阅读 C# 中的可变和不可变对象,我发现无论我在哪里读到的不变的东西是帽子是不可变的,这使得当用作哈希表中的键时线程安全且有用,但我不明白就概念而言虽然我们无法更改内容,但我们可以更改参考:
string s = "Hi";
s = "Bye";
虽然这里 s 的引用更改为“Bye”,但主要是 s 的内容(或者更确切地说它指向的内容)已经改变,并且从编程的角度来看是相同的,那么这是怎么回事如果字符串更改,则使特定函数线程安全或在哈希表中可用??
简单的。如果您要传递给在不同线程上运行的代码,则此代码将接收传递参数时s
指向的字符串。s
像 .net 中的所有字符串一样,它不会随着时间而改变,因此您的线程代码不需要考虑您可能会重新分配s
给不同的值。
如果您将“再见”分配给s
,则原始字符串将继续存在(直到其垃圾被收集),并且您的变量s
指向一个新字符串。
在字典中,略有不同。如果您更改可变键以使其哈希码发生变化,则字典将无法找到该键:哈希码用于在索引中搜索,如果哈希码随时间变化,字典将找不到正确的记录。所以这并不真正需要不变性,但不变性将确保哈希码的一致计算。
不变性对您的作用是它使您能够将对象视为一种值类型(例如 int),这通常更容易推理。
在您的示例中,s
重新分配以引用不同的string
对象(“Bye”),但s
之前引用的对象(“Hi”)没有改变。任何其他引用字符串“Hi”(另一个线程、aDictionary
等)的内容都不会受到影响。正如您所提到的,string
它是不可变的 - 它的内容一旦创建就无法更改。例如,如果您将一个附加string
到另一个,您将获得一个新string
对象。两个原始string
对象保持不变。这就是string
线程安全的原因,并且适合在哈希表中使用。
引用s
不是线程安全的 - 为了确保使用引用时的线程安全,您需要在引用分配周围加一个锁,以确保一个线程在另一个线程正在写入时不会尝试从引用中读取它。