C#中的System.String类型

6

我知道这可能听起来像一个奇怪的问题,但这已经在我的脑海中存在了一段时间。

我知道 C# 中的 System.String 类型实际上是一个具有字符数组参数的构造函数的类。例如,以下代码是合法的且不会引起错误:

System.String s = new System.String("Hello".toCharArray());

我的问题是,是什么让System.String类能够以这种简单的方式接受一个字符数组:

System.String s = "Hello";

4
编译器团队使这成为可能。就像其他字面量、Nullable<T>、扩展方法等一样。 - Adam Houldsworth
可能是因为它使用的索引器吗?如果是这样,那么它是如何做到的? - Transcendent
这是一种语言结构,就像if语句或var关键字一样。这只是语言的工作方式,string是一个特殊情况,以便更容易使用。 - Jeroen Vannevel
1
我的(天真的)猜测是,当您查看编译后的IL时,仅使用“Hello”语法创建字符串会生成一个“ldstr”IL指令,而使用带有数组的构造函数则创建了在行内创建“Hello”字符串的指令,调用“ ToCharArray”,然后将其传递给“String”构造函数。我猜这是CLR如何使用“ldstr”的实现细节,但除此之外,您的两个选项只是产生不同的IL指令。 - Chris Sinclair
2
这只是一个例子,证明编译器可以做一些你无法使用该语言实现的事情。 - Brian Rasmussen
3个回答

7

当您进行电话呼叫时:

System.String s = new System.String("Hello".toCharArray());

您正在显式调用构造函数

当您编写以下代码时:

string foo = "bar";

IL指令(Ldstr)会将一个新的对象引用推入该字符串文字。这并不相当于调用构造函数。


3
这是因为C#语言规定字符串字面量是可行的(详见§2.4.4.5字符串字面量)。C#编译器和CIL/CLR对这些字面量的使用有很好的支持,例如使用ldstr操作码。

然而,在自定义类型中包含此类字面量并不被支持。


-2

字符串是一种特殊的CLR类型。它们是唯一的不可变引用类型。

以下是几件事情,可能会帮助您了解字符串类型:

 var a = "Hello";
 var b = new String("Hello".ToCharArray());
 var c = String.Intern(b); // 'interns' the string...
 var equalsString = a == b;  // true
 var equalsObj =    (object)a == (object)b; // false
 var equalsInterned =    (object)a == (object)c; // true !!

 a[0] = 't'; // not valid, because a string is immutable. Instead, do it this way:
 var array = b.ToArray();
 array[0] = 't';
 a = new String(array); // a is now "tello"

它们是唯一的不可变引用类型。什么?真的吗?很抱歉,不是这样的。有很多不可变的引用类型。这里再给一个:public class Foo {} - Servy
@Servy 这是设计上的不可变性... 字符串是不可变的,因为CLR这样规定了,而不是程序员。 - Olivier
1
首先,实际上并没有任何真正的区别。其次,从技术上讲,字符串甚至不是不可变的,它们只是在其公共API中是不可变的。在内部,字符串可以被改变,在某些情况下实际上也确实被改变了,因此显然运行时不强制执行不可变性;很明显它允许这样做。 - Servy
3
我不明白这些内容如何回答这个问题。 - Jeroen Vannevel
@Servy “实际上被改变了”?我从未见过这种情况发生(只在纯托管代码中)。你有例子吗? - Olivier
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接