c# - регулярных - регулярные выражения примеры



Почему мы не используем новый оператор при инициализации строки? (5)

Мне задали этот вопрос в интервью: Является строкой ссылочный тип или тип значения.

Я сказал, что это ссылочный тип. Затем он спросил меня, почему мы не используем новый оператор при инициализации строки? Я сказал, потому что язык c # имеет более простой синтаксис для создания строки, и компилятор автоматически преобразует код в вызов для конструктора класса System.String.

Правильно ли этот ответ?


Answer #1

Вот мой прием, я не совсем уверен, поэтому отвечай мой ответ с солью.

Строковые литералы в .NET являются автономными, его длина или другая структура данных внутренне включается в собственно буквальное значение. Таким образом, в отличие от C, назначение строкового литерала в .NET - это просто назначение адреса памяти всей структуры данных строки. В C нам нужно использовать новое в строковом классе, так как ему нужно выделять другие структуры данных вокруг строки с нулевым завершением, например, длины.


Answer #2

Как говорят все, строка неизменна, поэтому невозможен вызов конструктора. Я хотел бы добавить следующую ссылку для вас, которая может немного очистить воздух:

Неизменяемость струны


Answer #3

Неа. Компилятор не меняет конструкцию. Каким должен быть аргумент конструктора? Строка? ;-)

Строковые литералы - это константы без имени.

Кроме того, вы можете инициализировать любой класс строковым литералом, если он поддерживает оператор:

   public class UnitTest1 {
      class MyStringable {
         public static implicit operator MyStringable(string value) {
            return new MyStringable();
         }
      }

      [TestMethod]
      public void MyTestMethod() {
         MyStringable foo = "abc";
      }
   }

Изменить Чтобы быть более ясным: как вы спросили, будет ли строка преобразована в любой вызов конструктора, давайте посмотрим на код IL.

Взял этот метод испытания:

   [TestClass]
   class MyClass {
      [TestMethod]
      public void MyTest() {
         string myString = "foo";
         if (myString == "bar")
            Console.WriteLine("w00t");
      }
   }

Создает следующий код IL:

.method public hidebysig instance void MyTest() cil managed
{
    .custom instance void [Microsoft.VisualStudio.QualityTools.UnitTestFramework]Microsoft.VisualStudio.TestTools.UnitTesting.TestMethodAttribute::.ctor()
    .maxstack 2
    .locals init (
        [0] string myString,
        [1] bool CS$4$0000)
    L_0000: nop 
    L_0001: ldstr "foo"
    L_0006: stloc.0 
    L_0007: ldloc.0 
    L_0008: ldstr "bar"
    L_000d: call bool [mscorlib]System.String::op_Equality(string, string)
    L_0012: ldc.i4.0 
    L_0013: ceq 
    L_0015: stloc.1 
    L_0016: ldloc.1 
    L_0017: brtrue.s L_0024
    L_0019: ldstr "w00t"
    L_001e: call void [mscorlib]System.Console::WriteLine(string)
    L_0023: nop 
    L_0024: ret 
}

Как вы видите, все строковые значения (foo, bar и w00t) по-прежнему являются строками и не вызывают никакого скрытого конструктора.

Надеюсь, это больше объясняет.


Answer #4

Но мы можем использовать новый оператор, чтобы инициализировать строку

String str = new char[] {'s','t','r'};

Правильно ли этот ответ?

Нет, строка кэшируется и используется, скажем, как есть в IL.


Answer #5

Строки являются неизменяемыми ссылочными типами. Существует команда ldstr IL, которая позволяет нажимать ссылку на новый объект на строковый литерал. Поэтому, когда вы пишете:

string a = "abc";

Компилятор проверяет, был ли литерал "abc" уже определен в метаданных, и если он не объявлен. Затем он переводит этот код в следующую инструкцию IL:

ldstr "abc"

Что в основном делает локальную переменную точкой для строкового литерала, определенного в метаданных.

Поэтому я бы сказал, что ваш ответ не совсем прав, поскольку компилятор не переводит это в призыв к конструктору.





.net