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

Как 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'

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

4b9b3361

Ответ 1

Необычно, как это может показаться, просто следуя правилам спецификации языка С#.

Из раздела 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 не имеет специальной оболочки в компиляторе С#, это будет эффективно:

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

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

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

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

Ответ 2

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

string operator +(string x, object y)

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

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

Ответ 3

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

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

Ответ 4

Интересно, что используя 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; на самом деле не принимается компилятором.

Ответ 5

null будет сбрасываться в пустую строку, и есть неявный конвертер из bool в строку, поэтому true будет передан в строку, а затем будет применен оператор +: он как: string 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

Ответ 6

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

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

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

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

Ответ 7

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...