【问题标题】:Using C# ternary with String.Equals将 C# 三元与 String.Equals 结合使用
【发布时间】:2014-08-01 14:38:02
【问题描述】:

这行得通:

short value;
value = 10 > 4 ? 5 : 10;

这行得通:

short value;
value = "test" == "test" ? 5 : 10;

这不起作用:

short value;
string str = "test";
value = "test" == str ? 5 : 10;

这个也不行:

short value;
string str = "test";
value = "test".Equals(str) ? 5 : 10;

最后两种情况我收到以下错误:

Cannot implicitly convert type 'int' to 'short'.
An explicit conversion exists (are you missing a cast?)

为什么我必须对最后两个案例而不是前两个案例进行强制转换?

【问题讨论】:

标签: c# .net


【解决方案1】:
short value;
value = 10 > 4 ? 5 : 10;             //1
value = "test" == "test" ? 5 : 10;   //2
string str = "test";
value = "test" == str ? 5 : 10;      //3
value = "test".Equals(str) ? 5 : 10; //4

最后两个三元表达式 (3,4) 在编译时无法解析为常量。因此编译器将510视为int字面量,整个三元表达式的类型为int。要从 int 转换为 short 需要显式转换。

前两个三元表达式 (1,2) 可以在编译时解析为常量。常量值为int,但编译器知道它适合short,因此不需要任何转换。

为了好玩,试试这个:

value = "test" == "test" ? 5 : (int)short.MaxValue + 1;

【讨论】:

  • 供参考:编译器实现的这种行为称为Constant Folding
  • @Groo -- 你知道正确答案不到 10 分钟。
  • Here's the MS Documentation 表示这可能发生。 “如果常量表达式的值在目标类型的范围内,则 int 类型的常量表达式可以转换为 sbyte、byte、short、ushort、uint 或 ulong。”但这并不能真正解释为什么编译器无法弄清楚 5 和 10 都可以是短裤,除了明显的“因为它不能”。
  • @ahruss 编译器绝对可以计算出 5 和 10 都可以是short。问题是,如果E 是表达式B ? X : Y,其中B 是非常量bool 表达式,那么E 总是被解释为非常量表达式,而不管X 和@ 987654340@ 是否恒定。如果X5 并且Y10,那么这些表达式的类型都是int。所以E 是非常量并且具有int 类型。非常量 int 不能隐式转换为 short
  • @ahruss(续) 编译器通过常量与非常量进行推理 - 它不为非常量变量保留界限。您建议的推理要求编译器说 B ? 5 : 10 始终是 [5, 10] 中的一个值。
【解决方案2】:

你需要一个演员来使最后两个例子工作

value = (short)("test" == str ? 5 : 10);

为什么前两个不需要它?

因为前两个是编译时常量。编译器能够将10 > 4 ? 5 : 10 转换为true ? 5 : 10,然后仅转换为5

所以当你写的时候

value = 10 > 4 ? 5 : 10;

实际上是一样的

value = 5;

编译是因为如果常量在允许的范围内,编译器可以隐式转换。

相反,"test" == str ? 5 : 10; 不是编译时间常数,因此不允许编译时隐式转换它。您需要自己进行显式转换。

【讨论】:

  • 完全正确。对于(short)("test" == str ? 5 : 10)"test" == str ? (short)5 : (short)10 之间的“学术”差异,请参阅我的回答。
【解决方案3】:

当然,这是由 C# 语言规范定义的。

要注意的关键是有两种转换 int short。一种是 显式 转换,它始终适用,但需要您在 int 表达式之前显式编写 (short)。另一种是 implicit constant expression conversion,它仅适用于 (a) int 表达式是编译时常量且 (b) 这个编译时表达式的值在short 的范围内,即-3276832767

5104 这样的文字在C# 中具有int 类型(适用于介于-21474836482147483647 之间且后面没有符号L 的任何整数文字、U 或类似名称)。因此,如果我们查看所有作业的右侧,它们显然是 int 表达式,而不是 short

10 > 4 ? 5 : 10 的情况下,由于104 是编译时常量,这与true ? 5 : 10 相同,因为> 运算符在ints 之间是内置的,将导致当操作数是常量时,在常量中。同样true ? 5 : 10 给出5,因为所有三个操作数都是常量,而?: 在这种情况下本身就被归类为常量。所以它真的说:

short value = 5;

其中“5”是编译时常量。因此,在编译时会检查 int 5 是否在范围内(与 10 无关,它可能是 999999),既然是这种情况,隐式常量表达式转换适用,而且是合法的。

请注意,您也可以这样做:

const int huge = 10;
const int tiny = 4;
const int significant = 5;
const int unimporatnt = 10;
short value;
value = huge > tiny ? significant : unimportant;

只要所有操作数都是const 变量(双关语?)。

现在,如果我设法解释清楚,您现在也会知道阻止value = "test" == str ? 5 : 10; 工作的障碍是您没有将str 本地标记为const。这样做,就会被允许。

使用Equals 电话,情况会更糟。调用Equals 的结果永远不会被视为编译时常量(我认为它不会被“优化”掉,例如"same".Equals("same") 实际上会在运行时调用该方法)。 (10).Equals(4)(10).CompareTo(4) > 0 等也会发生同样的情况,因此字符串在这方面并不特殊。


你很可能已经知道了

short value = cond ? 5 : 10;

不允许,因为cond 不是编译时常量,你只需要使用显式转换,所以写:

short value = cond ? (short)5 : (short)10;

或:

short value = (short)(cond ? 5 : 10);

从技术上讲,它们并不相同,因为第一个在运行时没有缩小转换(表达式 (short)5(short)10short 类型的文字),而最后一个必须转换 @ 987654372@ 到 short 在运行时(当然比难以置信的便宜)。


其他(未删除!)答案是正确的,这只是奖励信息。

【讨论】:

    【解决方案4】:

    问题是 10 > 4 ? 5 : 10; 实际上在编译时在需要任何类型转换之前转换为常量。这意味着编译器意识到,即使在编译需要任何隐式类型转换之前,turnary 语句实际上也可以简化为常量。所以换句话说,这个表达式是一样的:

    value = 5;
    

    在最后两个语句中,这是不正确的,因为您使用变量而不是常量来保存值。编译器不会检查变量的实际值是否可以将表达式简化为常量。所以你实际上需要演员表。

    【讨论】:

    • 不等于 value = 5 而不是 10?
    • 对。匆匆写下这个。固定。
    猜你喜欢
    • 1970-01-01
    • 2020-09-10
    • 1970-01-01
    • 1970-01-01
    • 2021-09-27
    • 2018-03-07
    • 2015-08-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多