String 同时为字符串对象指定与另一个字符串对象相同的文本,会使两者无意中指向同一对象。为什么?

String 同时为字符串对象指定与另一个字符串对象相同的文本,会使两者无意中指向同一对象。为什么?,string,vb.net,object,String,Vb.net,Object,考虑以下代码片段,特别是与应用于s1和s2的Is运算符有关的注释 Dim s1 As String = "1" Dim s2 As String = "2" Debug.Print((s1 Is s2).ToString) 'False - as expected s1 = s2 Debug.Print((s1 Is s2).ToString) 'True - as expected s1 = "3" Debug.Print((

考虑以下代码片段,特别是与应用于
s1
s2
Is
运算符有关的注释

    Dim s1 As String = "1"
    Dim s2 As String = "2"
    Debug.Print((s1 Is s2).ToString)    'False - as expected
    s1 = s2
    Debug.Print((s1 Is s2).ToString)    'True - as expected
    s1 = "3"
    Debug.Print((s1 Is s2).ToString)    'False - as expected
    s2 = "3"
    Debug.Print((s1 Is s2).ToString)    'True - wth?
    s2 = "4"
    Debug.Print((s1 Is s2).ToString)    'False - as expected

s2=“3”
赋值暂时使
s1
s2
对象相同。这背后的理由是什么?这没有潜在的危险吗?

发生的事情被称为

由于字符串是不可变的,.NET运行时将创建的字符串对象存储在表中以节省内存。每次在代码中声明一个pure(pure-as-in-declared,而不对其执行任何操作)字符串时,它都会检查该字符串是否已插入。如果是,那么.NET运行时将引用该内部实例,而不是创建一个全新的实例

公共语言运行库自动维护一个名为intern pool的表,该表包含程序中声明的每个唯一文本字符串常量的单个实例,以及通过调用intern方法以编程方式添加的字符串的任何唯一实例

例如:

Dim s1 As String = "a string" 'A pure, constant string.
Dim s2 As String = s1
Dim s3 As String = "this is " & s1 'Not pure: performing string concatenation.
Dim s4 As String = "this is a string"

Console.WriteLine("s1: " & s1)
Console.WriteLine("s2: " & s2)
Console.WriteLine("s3: " & s3)
Console.WriteLine("s4: " & s4)

Console.WriteLine("s1 Is s2: " & (s1 Is s2)) 'True
Console.WriteLine("s3 Is s4: " & (s3 Is s4)) 'False, s3 has not been interned and is its own instance.

在线测试:

发生的事情被称为

由于字符串是不可变的,.NET运行时将创建的字符串对象存储在表中以节省内存。每次在代码中声明一个pure(pure-as-in-declared,而不对其执行任何操作)字符串时,它都会检查该字符串是否已插入。如果是,那么.NET运行时将引用该内部实例,而不是创建一个全新的实例

公共语言运行库自动维护一个名为intern pool的表,该表包含程序中声明的每个唯一文本字符串常量的单个实例,以及通过调用intern方法以编程方式添加的字符串的任何唯一实例

例如:

Dim s1 As String = "a string" 'A pure, constant string.
Dim s2 As String = s1
Dim s3 As String = "this is " & s1 'Not pure: performing string concatenation.
Dim s4 As String = "this is a string"

Console.WriteLine("s1: " & s1)
Console.WriteLine("s2: " & s2)
Console.WriteLine("s3: " & s3)
Console.WriteLine("s4: " & s4)

Console.WriteLine("s1 Is s2: " & (s1 Is s2)) 'True
Console.WriteLine("s3 Is s4: " & (s3 Is s4)) 'False, s3 has not been interned and is its own instance.

在线测试:

编译器这样做是为了优化。您没有理由关心
字符串
引用所指的对象。您应该只关心两个
字符串的内容是否相同。这就是为什么您应该始终使用
=
来比较
字符串的原因;因此,您可以测试值相等,而不是引用相等。只有在与
进行比较时,才应将
字符串
一起使用,以便显式检测空引用。编译器这样做是为了优化。您没有理由关心
字符串
引用所指的对象。您应该只关心两个
字符串的内容是否相同。这就是为什么您应该始终使用
=
来比较
字符串的原因;因此,您可以测试值相等,而不是引用相等。唯一应该使用
的时间是
字符串
进行比较,以便显式检测空引用。“因此,每次创建“新”字符串时,它都会检查该字符串是否已被占用。”-这不是真的。@Enigmativity:为什么不是?它是否只插入常量字符串?编辑:是的,看起来是这样,我误解了MSDN。谢谢你的提醒!它只在编译时或在运行时显式插入字符串。没有检查现有的插入字符串。尝试此代码
object x=“a1”;object y=“a”+1.ToString();Console.WriteLine(x==y)-它打印
。将其更改为
object x=“a1”;对象y=“a1”;Console.WriteLine(x==y)并打印出
True
@Enigmativity:是的,我明白了。我也在答案中添加了一个代码示例(在手机上编写代码,所以我花了一点时间进行更新)。再次感谢@Enigmativity and Visual Vincent,谢谢你花时间向我解释幕后发生了什么。“所以每次你创建一个“新”字符串时,它都会检查该字符串是否已经被拘留。”-那不是真的。@Enigmativity:为什么不?它是否只插入常量字符串?编辑:是的,看起来是这样,我误解了MSDN。谢谢你的提醒!它只在编译时或在运行时显式插入字符串。没有检查现有的插入字符串。尝试此代码
object x=“a1”;object y=“a”+1.ToString();Console.WriteLine(x==y)-它打印
。将其更改为
object x=“a1”;对象y=“a1”;Console.WriteLine(x==y)并打印出
True
@Enigmativity:是的,我明白了。我也在答案中添加了一个代码示例(在手机上编写代码,所以我花了一点时间进行更新)。再次感谢@神秘和视觉文森特,谢谢你花时间向我解释幕后发生了什么。