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

标签 c# compiler-errors implicit-conversion

<分区>

Possible Duplicate:
Conditional operator cannot cast implicitly?
Why does null need an explicit type cast here?

我进行了搜索,但没有找到一个很好的解释来解释为什么会出现以下情况。
我有两个具有共同接口(interface)的类,我尝试使用如下所示的三元运算符初始化此接口(interface)类型的实例,但这无法编译并出现错误“无法确定条件表达式的类型,因为之间没有隐式转换'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();
}

如果我明确地将第一个条件转换到我的界面,这会起作用:

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

显然我总能做到这一点:

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

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

最佳答案

这是 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 被推断为提供的参数类型中的最佳类型,并且它们之间没有最佳类型。

有关此设计决策如何影响条件运算符行为的更多详细信息,请参阅 my series of articles on that topic .

如果您对为什么“从外到内”工作的重载决议是 NP-HARD 感兴趣,请参阅 this article .

关于c# - 三元条件下的隐式转换问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37706468/

相关文章:

ios - Xcode 崩溃后的 RestKit 错误

Scala 任何数字类型的隐式转换

arrays - 使用双指针指向二维数组

java - Eclipse IDE Java 隐式转换

c# - 返回 IEnumerable<T> 与 IQueryable<T>

c# - FluentValidation 多个验证器

c# - 有没有办法在 C# 中以编程方式登录 amazon.com?

c# - 在 Visual Studio 中调试时,是否可以在返回前找出返回值?

时间:2018-01-08 标签:c++mexerror: invalid types ‘double[mwSize]’ for array subscript

c++ - 在 C++ 中对来自全局函数的结构成员使用方法