Подтвердить что ты не робот

Почему результат добавления двух нулевых строк не равен нулю?

Я играл в С#, когда сталкивался с этим странным поведением в программировании .Net.

Я написал этот код:

  static void Main(string[] args)
    {
        string xyz = null;
        xyz += xyz;
        TestNullFunc(xyz);
        Console.WriteLine(xyz);

        Console.Read();

    }

    static void TestNullFunc(string abc)
    {
        if (abc == null)
        {
            Console.WriteLine("meow THERE ! ");
        }
        else
        {
            Console.WriteLine("No Meow ");
        }
    }

Я получил результат как No meow, что означает, что строка не null. Как это возможно? Почему добавление двух строк null приводит к строке не null?

При отладке, когда я проверяю значение xyz после добавления его к себе, его значение равно "" (без символов).

4b9b3361

Ответ 1

От MSDN:

В операциях конкатенации строк компилятор С# обрабатывает пустую строку так же, как пустую строку,

Несмотря на то, что xyz имеет значение null, вызов оператора + = (который преобразуется в вызов оператора + (*)), он не бросает a NullReferenceException, потому что это статический метод. В псевдокоде:

xyz = String.+(null, null);

Затем реализация интерпретирует это так, как если бы он был

xyz = String.+("", "");

(*) Раздел §7.17.2 спецификации С#:

Операция формы x op = y обрабатывается путем применения разрешения перегрузки бинарных операторов (§7.3.4), как если бы операция была записана x op y.

Ответ 2

Когда вы используете оператор +=, вы фактически вызываете метод string.Concat, который, как указано в документации:

Метод объединяет str0 и str1; он не добавляет разделителей. Пустая строка используется вместо любого нулевого аргумента.

Фактически этот код:

string xyz = null;
xyz += xyz;

будет скомпилирован в:

IL_0000:  ldnull      
IL_0001:  stloc.0     // xyz
IL_0002:  ldloc.0     // xyz
IL_0003:  ldloc.0     // xyz
IL_0004:  call        System.String.Concat
IL_0009:  stloc.0     // xyz

Ответ 3

Как указано, причиной является то, что конкатенация нуля считается такой же, как конкатенация пустой строки.

Стоит подумать, почему это поведение полезно.

Как правило, есть две разумные вещи, которые мы можем сделать с бинарным оператором, когда один из операндов имеет значение null:

  • Результат равен null.
  • Операция no-op, и мы остаемся с другим операндом.

Это имеет смысл, например, что ((int?)null) + 3 приводит к null, и обычно либо это будет самый полезный результат, либо тот, который мы будем сознательно защищать (то есть мы добавим код, чтобы поймать нулевое значение случай явно).

Но есть две причины не делать этого при конкатенации строк.

Во-первых, следует учитывать, что поскольку конкатенация означает не арифметический расчет, а совмещение двух вещей вместе, то что является самым разумным результатом приклеивания нулевого значения к началу или концу чего-то? Легко сделать так, чтобы это ничего не делало, а не возвращало null.

Во-вторых, на практике будет меньше случаев, когда мы хотим, чтобы a + b + c + d с строками возвращал значение null, если любой из них является нулевым, чем случаи, когда мы этого не сделали.

И из этого имеет смысл рассматривать null как пустую строку в конкатенациях. Исходя из этого, (string)null + (string)null приводит к "", потому что у нас нет специального случая для конкатенации слишком нулей.

Этот специальный случай можно добавить, но тогда свойство x + "" == x + null больше не будет выполняться, что может привести к некоторым странным случаям.

Ответ 4

Это потому, что оператор += добавляет строку Null to Empty.

поэтому компилятор добавляет пустую строку в существующий объект строки.

Итак, это Empty и Not null.

Ответ 5

попробуйте это...

static void TestNullFunc(string abc)
{
    if (string.IsNullOrEmpty( abc))
    {
        Console.WriteLine("meow THERE ! ");
    }
    else
    {
        Console.WriteLine("No Meow ");
    }
}

Ответ 6

С# заимствует поведение своего оператора + из Java. Если любой из операндов в + является строкой, оператор + вызывает String.Concat, который принимает тип Object и объединяет результаты вызова ToString на каждый непустой объект, который передается ему. Тот факт, что нулевые ссылки просто игнорируются, является лишь малой частью того, как операнды String.Concat не рассматриваются как "строки" как таковые; гораздо более заметным аспектом этого поведения является то, что типы, которые не являются строками, имеют свой метод ToString, независимо от того, были ли они иначе неявно конвертируемыми в string.