Как null + true строка?

Поскольку true не является строковым типом, как null + true строка?

string s = true;  //Cannot implicitly convert type 'bool' to 'string'   
bool b = null + true; //Cannot implicitly convert type 'string' to 'bool'

В чем причина этого?

113 голосов | спросил Javed Akram 17 FriEurope/Moscow2010-12-17T20:01:29+03:00Europe/Moscow12bEurope/MoscowFri, 17 Dec 2010 20:01:29 +0300 2010, 20:01:29

7 ответов


0

Как ни странно, это просто следование правилам спецификации языка C #.

Из раздела 7.3.4:

  

Операция вида x op y, где op - это перегружаемый двоичный оператор, x - это выражение типа X, а y - выражение типа Y, обрабатывается следующим образом:

     
  • Определяется набор возможных пользовательских операторов, предоставляемых X и Y для операционного оператора op (x, y). Набор состоит из объединения операторов-кандидатов, предоставленных X, и операторов-кандидатов, предоставленных Y, каждый из которых определяется по правилам §7.3.5. Если X и Y относятся к одному и тому же типу или если X и Y получены из общего базового типа, то операторы-кандидаты совместно используются в объединенном наборе только один раз.
  •   
  • Если набор пользовательских операторов-кандидатов не пуст, то он становится набором операторов-кандидатов для операции. В противном случае предопределенные реализации бинарных операторов, включая их поднятые формы, становятся набором операторов-кандидатов для операции. Предопределенные реализации данного оператора указываются в описании оператора (§7.8–7.12).
  •   
  • Правила разрешения перегрузки из §7.5.3 применяются к набору операторов-кандидатов для выбора лучшего оператора относительно списка аргументов (x, y), и этот оператор становится результатом процесса разрешения перегрузки. Если при разрешении перегрузки не удается выбрать лучший оператор, возникает ошибка времени привязки.
  •   

Итак, давайте рассмотрим это по очереди.

X здесь является нулевым типом - или вообще не типом, если вы хотите думать об этом таким образом. Он не предоставляет никаких кандидатов. Y - это bool, который не предоставляет пользовательский + операторы. Поэтому первый шаг не находит пользовательских операторов.

Затем компилятор переходит ко второй точке маркера, просматривая предопределенные двоичные операторы + реализации и их поднятые формы. Они перечислены в разделе 7.8.4 спецификации.

Если вы посмотрите на эти предопределенные операторы, то применим только тот, который применим: string operator +(string x, object y). Таким образом, набор кандидатов имеет одну запись. Это делает последний пункт очень простым ... разрешение перегрузки выбирает этот оператор, давая общий тип выражения string.

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

// Foo defined Foo operator+(Foo foo, bool b)
Foo f = null;
Foo g = f + true;

Это нормально, но он не используется для нулевого литерала, потому что компилятор не знает, как искать в Foo. Он знает только, что нужно учитывать string, потому что это предопределенный оператор, явно указанный в спецификации. (На самом деле это не оператор, определенный строковым типом ... 1 ) Это означает, что это не удастся скомпилировать:

// Error: Cannot implicitly convert type 'string' to 'Foo'
Foo f = null + true;

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

var x = null + 0; // x is Nullable<int>
var y = null + 0L; // y is Nullable<long>
var z = null + DayOfWeek.Sunday; // z is Nullable<DayOfWeek>

1 Вам может быть интересно, почему нет оператора string +. Это разумный вопрос, и я только угадываю ответ, но примите во внимание это выражение:

string x = a + b + c + d;

Если бы string не было специального регистра в компиляторе C #, это закончилось бы так же эффективно:

string tmp0 = (a + b);
string tmp1 = tmp0 + c;
string x = tmp1 + d;

Итак, создано две ненужные промежуточные строки. Однако, поскольку в компиляторе есть специальная поддержка, он на самом деле может скомпилировать вышеперечисленное как:

string x = string.Concat(a, b, c, d);

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

ответил Jon Skeet 17 FriEurope/Moscow2010-12-17T20:17:43+03:00Europe/Moscow12bEurope/MoscowFri, 17 Dec 2010 20:17:43 +0300 2010, 20:17:43
0

Причина в том, что как только вы вводите +, тогда вступают в силу правила привязки оператора C #. Он рассмотрит набор доступных операторов + и выберет наилучшую перегрузку. Одним из таких операторов является следующий

string operator +(string x, object y)

Эта перегрузка совместима с типами аргументов в выражении null + true. Следовательно, он выбирается в качестве оператора и оценивается как по существу ((string)null) + true, который оценивается как значение "True".

Раздел 7.7.4 спецификации языка C # содержит подробности об этом разрешении.

ответил JaredPar 17 FriEurope/Moscow2010-12-17T20:10:39+03:00Europe/Moscow12bEurope/MoscowFri, 17 Dec 2010 20:10:39 +0300 2010, 20:10:39
0

Компилятор отправляется на поиски оператора + (), который может сначала получить нулевой аргумент. Ни один из стандартных типов значений не подходит, для них значение NULL не является допустимым. Единственное совпадение - System.String.operator + (), двусмысленности нет.

Второй аргумент этого оператора также является строкой. Это происходит как капоэй, не может неявно конвертировать bool в строку.

ответил Hans Passant 17 FriEurope/Moscow2010-12-17T20:13:04+03:00Europe/Moscow12bEurope/MoscowFri, 17 Dec 2010 20:13:04 +0300 2010, 20:13:04
0

Интересно, что с помощью Reflector для проверки того, что сгенерировано, следующий код:

string b = null + true;
Console.WriteLine(b);

преобразуется в это компилятором:

Console.WriteLine(true);

Обоснование этой «оптимизации» немного странно, я должен сказать, и не рифмуется с выбором оператора, которого я ожидаю.

Кроме того, следующий код:

var b = null + true; 
var sb = new StringBuilder(b);

преобразуется в

string b = true; 
StringBuilder sb = new StringBuilder(b);

где string b = true; фактически не принимается компилятором.

ответил Peter Lillevold 17 FriEurope/Moscow2010-12-17T20:14:55+03:00Europe/Moscow12bEurope/MoscowFri, 17 Dec 2010 20:14:55 +0300 2010, 20:14:55
0

null будет приведен к нулевой строке, и существует неявный преобразователь из bool в строку, поэтому true будет приведен к строке, а затем будет применен оператор +: это как: строка str = "" + true.ToString ();

если вы проверите это с помощью Ildasm:

string str = null + true;

это как ниже:

.locals init ([0] string str)
  IL_0000:  nop
  IL_0001:  ldc.i4.1
  IL_0002:  box        [mscorlib]System.Boolean
  IL_0007:  call       string [mscorlib]System.String::Concat(object)
  IL_000c:  stloc.0
ответил Saeed Amiri 17 FriEurope/Moscow2010-12-17T20:11:12+03:00Europe/Moscow12bEurope/MoscowFri, 17 Dec 2010 20:11:12 +0300 2010, 20:11:12
0
var b = (null + DateTime.Now); // String
var b = (null + 1);            // System.Nullable<Int32> | same with System.Single, System.Double, System.Decimal, System.TimeSpan etc
var b = (null + new Object()); // String | same with any ref type

Сумасшедшие ?? Нет, причина должна быть в этом.

Кто-то звонит Eric Lippert ...

ответил decyclone 17 FriEurope/Moscow2010-12-17T20:12:58+03:00Europe/Moscow12bEurope/MoscowFri, 17 Dec 2010 20:12:58 +0300 2010, 20:12:58
0

Причиной этого является удобство (объединение строк является обычной задачей).

Как сказал BoltClock, оператор '+' определен для числовых типов, строк и может быть определен также для наших собственных типов (перегрузка операторов).

Если в типах аргумента нет перегруженного оператора '+' и они не являются числовыми типами, компилятор по умолчанию использует конкатенацию строк.

Компилятор вставляет вызов String.Concat(...), когда вы объединяете, используя '+', и реализация Concat вызывает ToString для каждого переданного объекта в это.

ответил quentin-starin 17 FriEurope/Moscow2010-12-17T20:05:56+03:00Europe/Moscow12bEurope/MoscowFri, 17 Dec 2010 20:05:56 +0300 2010, 20:05:56

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132