内联if和接口(多态)

时间:2010-01-20 16:57:41

标签: 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 ? new Bar() : new Bar();

4 个答案:

答案 0 :(得分:7)

编译器首先尝试评估右手表达式:

? new Foo() : new Bar();

这两者之间没有隐式转换因此错误消息。你可以这样做:

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

答案 1 :(得分:5)

这将在C#语言规范的第7.13节中介绍。基本上杀死这种情况的是,三元操作数的2个值的类型之间必须存在隐式转换。这种转换被认为是变量类型的绝对值。

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

后者2可以工作,因为他们只考虑1种类型(FooBar)。因为它们属于同一类型,所以确定表达式的类型很简单,并且工作正常。

答案 2 :(得分:4)

只需在此处发布的正确答案中添加一些内容:有两条设计指南可用于此规范。

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

double x = 2 + y;

我们首先计算出x的类型,然后是2的类型,然后是y的类型,然后是(2 + y)的类型,最后,我们计算x和(2 + y)是否兼容类型。但我们不会使用x的类型来决定2,y或2 + y的类型。

这是一个好规则的原因是因为“接收器”的类型通常正是我们想要解决的问题:

void M(Foo f) {}
void M(Bar b) {}
...
M(x ? y : z);

我们在这做什么?我们必须计算出条件表达式的类型才能进行重载解析,以确定它是否会转到Foo或Bar。因此,我们不能使用这个事实,比如,在我们对条件表达式类型的分析中去Foo!那是一个鸡蛋问题。

此规则的例外是lambda表达式,从其上下文中获取其类型。使该功能正常工作非常复杂;如果您有兴趣,请参阅我的blog series关于lambda表达式与匿名方法。

第二个要素是我们永远不会为你“魔术化”一种类型。如果给出了一些我们必须推断出类型的东西,我们总是推断出一种实际上正好在我们面前的类型。

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

  • 计算结果的类型
  • 计算出替代方案的类型
  • 找到与后果和替代
  • 兼容的最佳类型
  • 确保从条件表达式的类型转换为使用条件表达式的事物的类型。

与第一点保持一致,我们没有推理从外到内;我们不使用这样一个事实,即我们知道我们要去的变量的类型,以便计算出表达式的类型。但现在有趣的是,当你有

b ? new Cat() : new Dog()

我们说“条件表达式的类型是集{Cat,Dog}中的最佳类型”。我们不会说“条件表达式的类型是与Cat和Dog兼容的最佳类型”。那将是哺乳动物,但我们不这样做。相反,我们说“结果必须是我们实际看到的东西”,而在这两个选择中,两者都不是明显的赢家。如果你说

b ? (Animal) (new Cat()) : new Dog()

然后我们可以选择Animal和Dog,而Animal则是明显的赢家。

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

答案 3 :(得分:1)

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