为什么我们不在初始化字符串时使用new运算符?

tee*_*nup 35 .net c#

我在接受采访时被问到这个问题:字符串是引用类型还是值类型.

我说它是一个引用类型.然后他问我为什么不在初始化字符串时使用new运算符?我说因为c#语言有一个更简单的语法来创建一个字符串,编译器会自动将代码转换为对System.String类的construcor的调用.

这个答案是否正确?

Dar*_*rov 31

字符串是不可变的引用类型.有ldstr IL指令允许将新对象引用推送到字符串文字.所以当你写:

string a = "abc";
Run Code Online (Sandbox Code Playgroud)

编译器测试文件是否"abc"已在元数据中定义,如果没有声明它.然后它将此代码转换为以下IL指令:

ldstr "abc"
Run Code Online (Sandbox Code Playgroud)

这基本上使a局部变量指向元数据中定义的字符串文字.

所以我会说你的答案不太正确,因为编译器没有把它转化为对构造函数的调用.


Inc*_*ito 28

不完全正确的答案.字符串"特殊"引用类型.他们是不变的.编译器在内部执行某些操作是正确的,但它不是构造函数调用.它调用ldstr,它将新对象引用推送到存储在元数据中的字符串文字.

示例C#代码:

class Program
{
    static void Main()
    {
        string str;
        string initStr = "test";
    }
}
Run Code Online (Sandbox Code Playgroud)

这是IL代码

.method private hidebysig static void  Main() cil managed
{
  .entrypoint
  // Code size       8 (0x8)
  .maxstack  1
  .locals init ([0] string str,
           [1] string initStr)
  IL_0000:  nop
  IL_0001:  ldstr      "test"
  IL_0006:  stloc.1
  IL_0007:  ret
} // end of method Program::Main
Run Code Online (Sandbox Code Playgroud)

你可以看到ldstr上面的电话.

由于字符串的不变性,更可能只保留不同/唯一的字符串.所有字符串都保存在哈希表中,其中键是字符串值,值是对该字符串的引用.每当我们有一个新的字符串CLR检查时,哈希表中就已存在这样的字符串.如果没有,则分配新内存并将引用设置为此现有字符串.

您可以运行此代码来检查:

class Program
{
    static void Main()
    {
        string someString = "abc";
        string otherString = "efg";

        // will retun false
        Console.WriteLine(Object.ReferenceEquals(someString, otherString));

        someString = "efg";

        // will return true
        Console.WriteLine(Object.ReferenceEquals(someString, otherString));
    }
}    
Run Code Online (Sandbox Code Playgroud)


Guf*_*ffa 12

好吧,编译器具有简化字符串创建的特殊语法是正确的.

关于编译器产生对构造函数的调用的部分并不正确.应用程序启动时会创建字符串文字,因此在使用字符串文字时,它只是对已存在对象的引用的赋值.

如果在循环中指定字符串文字:

string[] items = new string[10];
for (int i = 0; i < 10; i++) {
  items[i] = "test";
}
Run Code Online (Sandbox Code Playgroud)

它不会为每次迭代创建一个新的字符串对象,它只会将相同的引用复制到每个项目中.

关于字符串文字的另外两个值得注意的事情是,编译器不会创建重复项,并且如果将它们连接起来,它会自动组合它们.如果您多次使用相同的文字字符串,它将使用相同的对象:

string a = "test";
string b = "test";
string c = "te" + "st";
Run Code Online (Sandbox Code Playgroud)

变量a,b并且c都指向同一个对象.

字符串类还包含可以使用的构造函数:

string[] items = new string[10];
for (int i = 0; i < 10; i++) {
  items[i] = new String('*', 42);
}
Run Code Online (Sandbox Code Playgroud)

在这种情况下,您将实际获得十个单独的字符串对象.