条件运算符不能隐式转换?

MPe*_*ier 61 c# types conditional-operator implicit-cast

我对这个小C#quirk感到有点难过:

给定变量:

Boolean aBoolValue;
Byte aByteValue;
Run Code Online (Sandbox Code Playgroud)

以下编译:

if (aBoolValue) 
    aByteValue = 1; 
else 
    aByteValue = 0;
Run Code Online (Sandbox Code Playgroud)

但这不会:

aByteValue = aBoolValue ? 1 : 0;
Run Code Online (Sandbox Code Playgroud)

错误说:"不能隐式地将类型'int'转换为'byte'."

当然,这个怪物会编译:

aByteValue = aBoolValue ? (byte)1 : (byte)0;
Run Code Online (Sandbox Code Playgroud)

这里发生了什么?

编辑:

使用VS2008,C#3.5

Eri*_*ert 69

这是一个经常被问到的问题.

在C#中,我们几乎总是从内到外推理.当你看到

x = y;
Run Code Online (Sandbox Code Playgroud)

我们计算出x的类型是什么,y的类型是什么,以及y的类型是否与x兼容.但是,当我们计算出y的类型时,我们不会使用这样一个事实,即我们知道x的类型是什么.

那是因为可能有不止一个x:

void M(int x) { }
void M(string x) { }
...
M(y); // y is assigned to either int x or string x depending on the type of y
Run Code Online (Sandbox Code Playgroud)

我们需要能够计算表达式的类型,而不知道它被分配给什么.型信息流出来的表达,而不是的表达式.

为了计算出条件表达式的类型,我们计算出结果的类型和替代表达式,选择两种类型的更一般,并且它成为条件表达式的类型.所以在你的例子中,条件表达式的类型是"int",它不是常量(除非条件表达式是常量true或常量false).由于它不是常量,因此不能将其分配给字节; 当结果不是常量时,编译器仅从类型而不是从值中推断出原因.

所有这些规则的例外是lambda表达式,其中类型信息确实从上下文流入lambda.获得正确的逻辑非常困难.

  • 我的思绪被吹了.谢谢,先生,这是一部分启发和两部分令人沮丧.一个是因为它不能像它看起来那样工作,而另外两个因为它无法以这种方式工作是有道理的.所以...它是常数! (2认同)
  • @Eric Lippert,我试图评论你的博客文章,但我不确定是否花了,所以我在这里问:不是试图单独解决类型,为什么编译器不转换整个三元表达式到等效的"详细表达式"(在这种情况下,`byte aByteValue; if(aBoolValue)aByteValue = 1;否则aByteValue = 0;`)?是否有一些问题会使这不可行?或者它是一个哲学的东西(例如,"如果它看起来像一个表达式,它应该被评估为一个.")?我认为大多数程序员最初都希望三元工作完全像if-else一样. (2认同)

Joh*_*ler 12

我正在使用VS 2005,因为我可以重现,对于bool和布尔,但不是真的

 bool abool = true;
 Boolean aboolean = true;
 Byte by1 = (abool ? 1 : 2);    //Cannot implicitly convert type 'int' to 'byte'
 Byte by2 = (aboolean ? 1 : 2); //Cannot implicitly convert type 'int' to 'byte'
 Byte by3 = (true ? 1 : 2);     //Warning: unreachable code ;)
Run Code Online (Sandbox Code Playgroud)

最简单的解决方法似乎是这个演员

 Byte by1 = (Byte)(aboolean ? 1 : 2);
Run Code Online (Sandbox Code Playgroud)

所以,是的,似乎三元运算符导致常量将其类型"修复"为整数并禁用隐式类型转换,否则您将从适合较小类型的常量中获取.


Ham*_*jan 7

我可能没有给你一个很好的答案,但如果你在很多地方这样做,你可以宣布:

private static readonly Byte valueZero = (byte)0;
private static readonly Byte valueOne = (byte)1;
Run Code Online (Sandbox Code Playgroud)

而这些变量.const如果它是项目的本地,您可能会使用它.

编辑:使用readonly没有意义 - 这些都不是要改变.

  • @Hamish:我明白你的意思了.我可以使用const,但它是一种解决方法.这肯定不值得你投票下来. (2认同)