C# 内联if和接口(多态性)

C# 内联if和接口(多态性),c#,.net-3.5,interface,inline-if,C#,.net 3.5,Interface,Inline If,那么,为什么这不会编译 public class Foo : IFooBarable {...} public class Bar : IFooBarable {...} 但这将 int a = 1; IFooBarable ting = a == 1 ? new Foo() : new Bar(); 编译器首先尝试计算右侧表达式: IFooBarable ting = a == 1 ? new Foo() : new Foo(); IFooBarable ting = a == 1 ? n

那么,为什么这不会编译

public class Foo : IFooBarable {...}
public class Bar : IFooBarable {...}
但这将

int a = 1;
IFooBarable ting = a == 1 ? new Foo() : new Bar();

编译器首先尝试计算右侧表达式:

IFooBarable ting = a == 1 ? new Foo() : new Foo();
IFooBarable ting = a == 1 ? new Bar() : new Bar();
这两者之间没有隐式转换,因此出现错误消息。您可以这样做:

? new Foo() : new Bar();

编译器首先尝试计算右侧表达式:

IFooBarable ting = a == 1 ? new Foo() : new Foo();
IFooBarable ting = a == 1 ? new Bar() : new Bar();
这两者之间没有隐式转换,因此出现错误消息。您可以这样做:

? new Foo() : new Bar();

C#语言规范第7.13节介绍了这一点。从本质上讲,扼杀这一场景的是三值操作数的2个值的类型之间必须存在隐式转换。在变量类型不存在时考虑此转换

因此,
Foo
必须可转换为
Bar
,反之亦然。两者都不是,因此会发生编译错误


后面的2则是因为它们只考虑了1种类型(无论是代码> Foo还是<代码> BAR < /代码>。因为它们属于同一类型,所以确定表达式的类型很简单,而且工作正常。

这在C语言规范的第7.13节中有介绍。基本上,消除这种情况的原因是三元操作数的2个值的类型之间必须存在隐式转换。在变量类型不存在时考虑此转换

因此,
Foo
必须可转换为
Bar
,反之亦然。两者都不是,因此会发生编译错误


后面的2则是因为它们只考虑了1种类型(无论是代码> Foo还是<代码> BAR < /代码>。因为它们属于同一类型,所以确定表达式的类型很简单,而且工作正常。

因为条件表达式的类型总是从它的两个部分推断出来的,而不是从要应用结果的变量推断出来的。只有当类型相等或一个引用与另一个兼容时,此推断才有效。在这种情况下,这两种类型都与另一种类型的引用不兼容。

因为条件表达式的类型总是从它的两个部分推断出来的,而不是从要应用结果的变量推断出来的。只有当类型相等或一个引用与另一个兼容时,此推断才有效。在这种情况下,这两种类型都与另一种类型不兼容。

仅为此处发布的正确答案添加一点内容:有两种设计准则导致了本规范

首先,我们从“内部到外部”进行推理。当你说

IFooBarable ting = a == 1 ? (IFooBarable)(new Foo()) : (IFooBarable)(new Bar());
我们首先计算x的类型,然后计算2的类型,然后计算y的类型,然后计算(2+y)的类型,最后计算x和(2+y)是否有兼容的类型。但是我们不使用x的类型来决定2,y或2+y的类型

这是一个好规则的原因是,通常“接收者”的类型正是我们试图解决的问题:

double x = 2 + y;
我们在这里干什么?为了进行重载解析,我们必须计算出条件表达式的类型,以便确定这是Foo还是Bar。因此,我们不能在分析条件表达式的类型时使用这一事实,比如说,使用Foo!这是鸡和蛋的问题

此规则的例外是lambda表达式,它确实从上下文中获取其类型。使这一功能正常工作是极其复杂的;如果您感兴趣,请参阅我的关于lambda表达式与匿名方法的文章

第二个要素是,我们从不为您“创造”一种类型。当我们从一堆东西中推断出一种类型时,我们总是推断出一种实际上就在我们面前的类型

在您的示例中,分析如下所示:

  • 计算出后果的类型
  • 计算出备选方案的类型
  • 找到与结果和备选方案兼容的最佳类型
  • 确保从条件表达式的类型转换为使用条件表达式的对象的类型
按照第一点,我们不从外向内推理;我们不用知道变量的类型这一事实来计算表达式的类型。但现在有趣的是当你

void M(Foo f) {}
void M(Bar b) {}
...
M(x ? y : z);
我们说“条件表达式的类型是集合{Cat,Dog}中的最佳类型”。我们并没有说“条件表达式的类型是与Cat和Dog兼容的最佳类型”。那可能是哺乳动物,但我们不这么做。相反,我们说“结果必须是我们实际看到的”,在这两个选择中,没有一个是明确的赢家。如果你说

b ? new Cat() : new Dog()
然后我们可以在动物和狗之间做出选择,动物显然是赢家


现在,请注意,在进行此类型分析时,我们实际上没有正确实现C#规范!有关错误的详细信息,请参阅my on it.

仅为此处发布的正确答案添加一点内容:有两个设计准则导致了此规范

首先,我们从“内部到外部”进行推理。当你说

IFooBarable ting = a == 1 ? (IFooBarable)(new Foo()) : (IFooBarable)(new Bar());
我们首先计算x的类型,然后计算2的类型,然后计算y的类型,然后计算(2+y)的类型,最后计算x和(2+y)是否有兼容的类型。但是我们不使用x的类型来决定2,y或2+y的类型

这是一个好规则的原因是,通常“接收者”的类型正是我们试图解决的问题:

double x = 2 + y;
我们在这里干什么?为了进行重载解析,我们必须计算出条件表达式的类型,以便确定这是Foo还是Bar。因此,我们不能在分析条件表达式的类型时使用这一事实,比如说,使用Foo!这是鸡和蛋的问题

这个规则的例外是lambda表达式,它的类型来自t