【问题标题】:inline if and interfaces (polymorphism)内联 if 和接口(多态性)
【发布时间】:2011-01-07 09:02:17
【问题描述】:
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();

【问题讨论】:

  • 这个特性最糟糕的副作用是int? x = condition ? 42 : null;编译失败:(

标签: c# .net-3.5 interface inline-if


【解决方案1】:

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

? new Foo() : new Bar();

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

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

【讨论】:

  • IFooBarable ting = a == 1 ? (IFooBarable)new Foo() : new Bar() ;)
【解决方案2】:

C# 语言规范的第 7.13 节对此进行了介绍。基本上杀死这种情况的是,三元操作数的 2 个值的类型之间必须存在隐式转换。这种转换是在没有变量类型的情况下考虑的。

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

后 2 个工作,因为它们只考虑 1 种类型(FooBar)。因为它们属于同一类型,所以确定表达式的类型很简单,而且效果很好。

【讨论】:

    【解决方案3】:

    只是在此处发布的正确答案中添加一点:有两个设计指南导致了此规范。

    首先是我们“由内而外”的推理。当你说

    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就可以了。

    【讨论】:

    • "...与 Cat 和 Dog 兼容的最佳类型。那将是 Mammal..." 实际上,CatDog 类都派生自 Carnivora,但无论如何. ;-)
    【解决方案4】:

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

    【讨论】:

      猜你喜欢
      • 2011-02-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-06-25
      • 1970-01-01
      • 2021-12-31
      • 2012-12-23
      • 2015-04-17
      相关资源
      最近更新 更多