一尘不染

三元条件下的隐式转换问题

c#

这个问题已经在这里有了答案

8年前关闭。

可能重复:
条件运算符不能隐式转换吗?
为什么null需要在此处强制转换为显式类型?

我进行了搜索,但没有找到关于以下原因的良好解释。
我有两个具有共同接口的类,并且尝试使用如下三元运算符初始化此接口类型的实例,但这无法编译,且错误为“无法确定条件表达式的类型,因为之间没有隐式转换’xxx.Class1’和’xxx.Class2’:

public ConsoleLogger : ILogger  { .... }

public SuppressLogger : ILogger  { .... }

static void Main(string[] args)
{
   .....
   // The following creates the compile error
   ILogger logger = suppressLogging ? new SuppressLogger() : new ConsoleLogger();
}

如果我将第一个conditioin显式转换为我的界面,则此方法有效:

   ILogger logger = suppressLogging ? ((ILogger)new SuppressLogger()) : new ConsoleLogger();

很明显,我总是可以做到这一点:

   ILogger logger;
   if (suppressLogging)
   {
       logger = new SuppressLogger();
   }
   else
   {
       logger = new ConsoleLogger();
   }

替代方法很好,但是我不能完全理解为什么第一个选项会因隐式转换错误而失败,因为在我看来,这两个类都是ILogger类型,并且我并不是真正地在进行转换(隐式或显式)。
)。我确定这可能是静态语言编译问题,但我想了解发生了什么。


阅读 439

收藏
2020-05-19

共1个答案

一尘不染

这是C#的两个特征融合的结果。

首先是C#永远不会为您“神奇”一个类型。如果C#必须从一组给定类型中确定“最佳”类型,则它总是选择您提供的一种类型。它从未说过:“您给我的类型都不是最好的类型;由于您给我的选择都是不好的,所以我将挑选一些您没有给我的随机选择。”

第二个是从C#原因 里面外面 。我们不会说“哦,我看到您正在尝试将条件运算符结果分配给ILogger;让我确保两个分支都起作用。”
相反的情况发生了:C#说“让我确定两个分支返回的最佳类型,并验证最佳类型是否可以转换为目标类型。”

第二条规则是明智的,因为 目标类型可能是我们要确定的目标类型。 当您说D d = b ? c : a;清楚目标类型是什么时。但是,假设您打电话给您M(b?c:a)?M可能有一百种不同的重载,每种重载都具有形式参数的不同类型!我们必须确定参数的类型,然后丢弃M的重载,这是不适用的,因为参数类型与形式参数不兼容。我们不会走另一条路。

考虑如果我们采取其他方式会发生什么:

M1( b1 ? M2( b3 ? M4( ) : M5 ( ) ) : M6 ( b7 ? M8() : M9() ) );

假设每个M1,M2和M6都有一百个过载。你是做什么?您是否说好,如果这是M1(Foo),则M2(…)和M6(…)必须都可以转换为Foo。是吗
让我们找出答案。M2的过载是多少?有一百种可能性。让我们看看它们中的每一个是否都可以从M4和M5的返回类型转换而来…好吧,我们已经尝试了所有这些,所以我们找到了一个可以工作的M2。现在M6呢?如果我们发现“最佳”
M2与“最佳” M6不兼容怎么办?我们是否应该回溯并继续重试所有100 x 100的可能性,直到找到兼容的对?问题变得越来越严重。

我们 这样做的 原因是lambda,因此涉及lambda的重载解析至少在C#中为NP-HARD。那很不好 我们宁愿不为编译器添加更多的NP-
HARD问题来解决。

您还可以在该语言的其他位置看到正在运行的第一条规则。例如,如果您说: ILogger[] loggers = new[] { consoleLogger, suppressLogger };您将收到类似的错误;推断的数组元素类型必须是给定类型表达式的 最佳类型
。如果无法从中确定最佳类型,我们不会尝试查找您没有给我们的类型。

类型推断也一样。如果你说:

void M<T>(T t1, T t2) { ... }
...
M(consoleLogger, suppressLogger);

这样就不会推断T为ILogger;这将是一个错误。在提供的参数类型中,T被推断为最佳类型,并且在它们之间没有最佳类型。

有关此设计决策如何影响条件运算符的行为的更多详细信息,请参阅我关于该主题的系列文章

如果您对为什么“从外部到内部”有效的过载解析是NP-
HARD感兴趣,请参阅本文

2020-05-19