Как работает добавление к пустой строке в C #? - PullRequest
44 голосов
/ 31 октября 2011

Я был удивлен, увидев пример строки, которая инициализируется нулем, а затем что-то добавляется к ней в производственной среде.Это просто пахло неправильно.

Я был уверен, что это вызвало бы исключение нулевого объекта, но этот сильно уменьшенный пример также работает:

string sample = null;
sample += "test";
// sample equals "test"

* Обратите внимание на оригинальный код, который я нашел, устанавливаетстроковое свойство для нуля и добавление к нему в другом месте, поэтому ответы с участием компилятора, оптимизирующего нулевое значение во время компиляции, не имеют значения.

Может кто-нибудь объяснить, почему это работает без ошибок?

Продолжение:

Основываясь на ответе Леппи, я использовал Reflector, чтобы увидеть, что находится внутри string.Concat.Теперь совершенно очевидно, почему происходит это преобразование (вообще без магии):

public static string Concat(string str0, string str1)
{
    if (IsNullOrEmpty(str0))
    {
        if (IsNullOrEmpty(str1))
        {
            return Empty;
        }
        return str1;
    }
    if (IsNullOrEmpty(str1))
    {
        return str0;
    }
    int length = str0.Length;
    string dest = FastAllocateString(length + str1.Length);
    FillStringChecked(dest, 0, str0);
    FillStringChecked(dest, length, str1);
    return dest;
}

** Примечание: конкретная реализация, которую я исследовал (в библиотеке .Net от Microsoft), непреобразовать в пустые строки, как это предусмотрено стандартами C # и большинством ответов, но использует несколько тестов для ускорения процесса.Конечный результат такой же, как если бы он это сделал, но все готово:)

Ответы [ 4 ]

47 голосов
/ 31 октября 2011

оператор + для строк - это просто сокращение для string.Concat, которое просто превращает null аргументы в пустые строки перед объединением.

Обновление:

Обобщенная версия string.Concat:

public static string Concat(params string[] values)
{
    int num = 0;
    if (values == null)
    {
        throw new ArgumentNullException("values");
    }
    string[] array = new string[values.Length];
    for (int i = 0; i < values.Length; i++)
    {
        string text = values[i];
        array[i] = ((text == null) ? string.Empty : text);
        num += array[i].Length;
        if (num < 0)
        {
            throw new OutOfMemoryException();
        }
    }
    return string.ConcatArray(array, num);
}
7 голосов
/ 31 октября 2011

Соответствующая цитата должна быть ECMA-334 §14.7.4:

Конкатенация строк:

string operator +(string x, string y);
string operator +(string x, object y);
string operator +(object x, string y);  

Бинарный оператор + выполняет конкатенацию строк, когда один или оба операнда имеют тип string. Если операнд строки конкатенация null, подставляется пустая строка. В противном случае любой нестроковый операнд преобразуется в его строковое представление вызов виртуального метода ToString, унаследованного от типа object. Если ToString возвращает null, подставляется пустая строка.

3 голосов
/ 31 октября 2011

это потому что

В операциях конкатенации строк компилятор C # обрабатывает нуль строка такая же как пустая строка, но она не преобразует значение исходной нулевой строки.

С Как: объединить несколько строк (Руководство по программированию в C #)

Бинарный оператор + выполняет конкатенацию строк, когда один или оба операнды имеют тип string. Если операнд конкатенации строк null, подставляется пустая строка. В противном случае, любой не-строка аргумент преобразуется в его строковое представление, вызывая виртуальный метод ToString, унаследованный от объекта типа. Если ToString возвращает ноль, подставляется пустая строка.

С Оператор сложения

1 голос
/ 31 октября 2011

Вот к чему ваш код компилируется

string sample = null;
sample += "test";

компилируется в этот код IL:

.entrypoint
  // Code size       16 (0x10)
  .maxstack  2
  .locals init ([0] string sample)
  IL_0000:  nop
  IL_0001:  ldnull
  IL_0002:  stloc.0
  IL_0003:  ldloc.0
  IL_0004:  ldstr      "test"
  IL_0009:  call       string [mscorlib]System.String::Concat(string,
                                                              string)
  IL_000e:  stloc.0
  IL_000f:  ret

И String.Concat заботится о пустой строке.

...