null + true是一个字符串怎么样?

Jav*_*ram 112 .net c# string null types

既然true不是字符串类型,字符串怎么样null + true

string s = true;  //Cannot implicitly convert type 'bool' to 'string'   
bool b = null + true; //Cannot implicitly convert type 'string' to 'bool'
Run Code Online (Sandbox Code Playgroud)

这背后的原因是什么?

Jon*_*eet 148

这看起来很奇怪,它只是遵循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是从公共基类型派生的,则共享候选运算符仅出现在组合集中一次.
  • 如果候选用户定义的运算符集合不为空,则这将成为该操作的候选运算符集.否则,预定义的二元运算符op实现(包括它们的提升形式)将成为该操作的候选运算符集.给定运算符的预定义实现在运算符的描述中指定(第7.7节到第7.12节).
  • §7.5.3的重载决策规则应用于候选运算符集合,以根据参数列表(x,y)选择最佳运算符,并且此运算符成为重载解析过程的结果.如果重载决策未能选择单个最佳运算符,则会发生绑定时错误.

那么,让我们依次介绍一下.

X是这里的null类型 - 或者根本不是类型,如果你想这样想的话.它没有提供任何候选人.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;
Run Code Online (Sandbox Code Playgroud)

这很好,但它不用于null文字,因为编译器不知道要查看Foo.它只知道要考虑string因为它是规范中明确列出的预定义运算符.(实际上,它不是由字符串类型定义的运算符... 1)这意味着这将无法编译:

// Error: Cannot implicitly convert type 'string' to 'Foo'
Foo f = null + true;
Run Code Online (Sandbox Code Playgroud)

其他第二操作数类型将使用其他一些运算符,当然:

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>
Run Code Online (Sandbox Code Playgroud)

1您可能想知道为什么没有字符串+运算符.这是一个合理的问题,我只是在猜测答案,但请考虑这个表达式:

string x = a + b + c + d;
Run Code Online (Sandbox Code Playgroud)

如果string在C#编译器中没有特殊的外壳,这将最终有效:

string tmp0 = (a + b);
string tmp1 = tmp0 + c;
string x = tmp1 + d;
Run Code Online (Sandbox Code Playgroud)

这样就创建了两个不必要的中间字符串.但是,因为编译器中有特殊的支持,它实际上能够将上面的代码编译为:

string x = string.Concat(a, b, c, d);
Run Code Online (Sandbox Code Playgroud)

它可以只创建一个完全正确长度的单个字符串,只复制一次所有数据.尼斯.

  • 在20分钟内.他在20分钟内完成了这一切.他应该写书或者等等......哦等等. (47认同)
  • @leppie:表达式*是*有效,其类型是字符串.试试"var x = null + true;" - 它编译并且`x`是`string`类型.请注意,这里使用的签名是`string operator +(string,object)` - 它将`bool`转换为`object`(这很好),而不是`string`. (6认同)

Jar*_*Par 44

原因是因为一旦你引入+了C#运算符绑定规则就会发挥作用.它将考虑+可用的运算符集并选择最佳过载.其中一个运营商如下

string operator +(string x, object y)
Run Code Online (Sandbox Code Playgroud)

此重载与表达式中的参数类型兼容null + true.因此,它被选择作为运算符并且被评估为基本上((string)null) + true评估该值"True".

C#语言规范的第7.7.4节包含有关此分辨率的详细信息.


Han*_*ant 11

编译器会寻找可以先取空参数的运算符+().没有标准值类型限定,null不是它们的有效值.唯一匹配的是System.String.operator +(),没有歧义.

该运算符的第二个参数也是一个字符串.那就是kapooey,不能隐含地将bool转换为字符串.


Pet*_*old 10

有趣的是,使用Reflector检查生成的内容,代码如下:

string b = null + true;
Console.WriteLine(b);
Run Code Online (Sandbox Code Playgroud)

由编译器转换为this:

Console.WriteLine(true);
Run Code Online (Sandbox Code Playgroud)

这个"优化"背后的原因有点奇怪,我必须说,并没有与我期望的运算符选择押韵.

另外,以下代码:

var b = null + true; 
var sb = new StringBuilder(b);
Run Code Online (Sandbox Code Playgroud)

变成了

string b = true; 
StringBuilder sb = new StringBuilder(b);
Run Code Online (Sandbox Code Playgroud)

这里string b = true;实际上没有编译器所接受.


Sae*_*iri 8

null将被转换为null字符串,并且存在从bool到string的隐式转换器,因此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
Run Code Online (Sandbox Code Playgroud)


que*_*rin 5

这样做的原因是方便(连接字符串是一项常见任务).

正如BoltClock所说,'+'运算符是在数字类型,字符串上定义的,也可以为我们自己的类型定义(运算符重载).

如果参数的类型上没有重载的"+"运算符且它们不是数字类型,则编译器默认为字符串连接.

编译器String.Concat(...)在使用"+"连接时插入一个调用,并且Concat的实现在传递给它的每个对象上调用ToString.


dec*_*one 5

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
Run Code Online (Sandbox Code Playgroud)

疯??不,背后必然有一个原因.

有人打电话Eric Lippert......