假设两个类,都是同一个超类的后代,如下所示:
class MySuperClass{}
class A : MySuperClass{}
class B : MySuperClass{}
那么这个赋值就不会通过编译器:
MySuperClass p = myCondition ? new A() : new B();
编译器抱怨 A 和 B 不兼容(无法确定条件表达式的类型,因为“A”和“B”之间没有隐式转换[CS0173])。但它们都是 MySuperClass 类型,所以在我看来这应该可行。并不是说这有什么大不了的。一个简单的转换就足以启发编译器。但这肯定是 C# 编译器中的一个障碍吗?你不同意吗?
条件的结果应该是同一类型。他们不是。
来自 MSDN,(?:操作员):
first_expression 和 secondary_expression 的类型必须相同,或者必须存在从一种类型到另一种类型的隐式转换。
由于
A
和 B
不是同一类型,并且您似乎没有定义隐式转换,因此编译器会抱怨。
请参阅语言规范第 7.14 节
第二个和第三个操作数 x 和 y, ?: 操作符控制类型 条件表达式的。
· 如果 x 具有类型 X 并且 y 具有 然后输入 Y
o 如果隐式转换(第 6.1 节) 从 X 到 Y 存在,但从 Y 到不存在 X,则 Y 是类型 条件表达式。
o 如果隐式转换(第 6.1 节) 从 Y 到 X 存在,但从 X 到 X 不存在 Y,则 X 是类型 条件表达式。
o 否则,任何表达式类型都不能 被确定,并且编译时 发生错误。
· 如果 x 和 y 中只有一个有 x 和 y 的类型 可以隐式转换为 type,那么这就是 条件表达式。
· 否则,无法确定表达式类型,并发生编译时错误。
本质上,操作数必须可以相互转换为,而不是相互转换为其他类型。
这就是为什么您需要在示例中或在可空值等情况下进行显式转换 (int? foo = isBar ? 42 : (int?)null
)。声明类型不会影响计算,编译器必须从表达式本身中找出它。
博客,了解一些有趣的文章,了解为什么 C# 编译器会/不执行对您来说“显而易见”的事情。该博客由 Eric Lippert 撰写,他是 C# 编译器开发人员之一。
MySuperClass p = myCondition ? (MySuperClass)(new A()) : (MySuperClass)(new B());
这意味着条件运算符两边返回相同的类型,这满足了编译器的要求。
object
吗?那么值类型又会被隐式装箱吗?接口怎么样?如果两种类型之间有多个公共接口,应该选择哪一种?在您的情况下,正如您所发现的,您需要将其中一个操作数向上转换为父类型。一旦你这样做了,规则 2.) 就得到满足(总是存在从更具体的类型到不太具体的类型的隐式转换)。
请注意,您只需将强制转换应用于其中一个操作数,而不是同时应用于两个。
object
来代替。