三元条件下的隐式转换问题 [英] Implicit conversion issue in a ternary condition

查看:12
本文介绍了三元条件下的隐式转换问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

可能的重复:
条件运算符不能隐式转换?
为什么 null 需要显式类型转换?

我进行了搜索,但没有找到有关为什么会发生以下情况的良好解释.
我有两个类,它们有一个共同的接口,我尝试使用三元运算符初始化此接口类型的实例,如下所示,但这无法编译,并显示错误无法确定条件表达式的类型,因为它们之间没有隐式转换xxx.Class1"和xxx.Class2":

I've had a search and haven't found a good explanation for why the following occurs.
I have two classes which have an interface in common and I have tried initializing an instance of this interface type using the ternary operator as below but this fails to compile with the error "Type of conditional expression cannot be determined because there is no implicit conversion between 'xxx.Class1' and '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();
}

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

This works if I explicitly cast the first conditioin to my interface:

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

显然我总是可以做到这一点:

and obviously I can always do this:

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

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

The alternatives are fine but I can't quite get my head around why the first option fails with the implicit conversion error as, in my view, both classes are of type ILogger and I am not really looking to do a conversion (implicit or explicit). I'm sure this is probably a static language compilation issue but I would like to understand what is going on.

推荐答案

这是 C# 的两个特性融合的结果.

This is a consequence of the confluence of two characteristics of C#.

首先是 C# 永远不会为您魔术"一个类型.如果 C# 必须从一组给定的类型中确定一个最佳"类型,它总是会选择你给它的类型之一.它从不说你给我的类型都不是最好的类型;既然你给我的选择都很糟糕,我就随便挑一些你没有给我选择的东西."

The first is that C# never "magics up" a type for you. If C# must determine a "best" type from a given set of types, it always picks one of the types you gave it. It never says "none of the types you gave me are the best type; since the choices you gave me are all bad, I'm going to pick some random thing that you did not give me to choose from."

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

The second is that C# reasons from inside to outside. We do not say "Oh, I see you are trying to assign the conditional operator result to an ILogger; let me make sure that both branches work." The opposite happens: C# says "let me determine the best type returned by both branches, and verify that the best type is convertible to the target type."

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

The second rule is sensible because the target type might be what we are trying to determine. When you say D d = b ? c : a; it is clear what the target type is. But suppose you were instead calling M(b?c:a)? There might be a hundred different overloads of M each with a different type for the formal parameter! We have to determine what the type of the argument is, and then discard overloads of M which are not applicable because the argument type is not compatible with the formal parameter type; we don't go the other way.

想想如果我们走另一条路会发生什么:

Consider what would happen if we went the other way:

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 的可能性,直到找到兼容的对?问题越来越严重.

Suppose there are a hundred overloads each of M1, M2 and M6. What do you do? Do you say, OK, if this is M1(Foo) then M2(...) and M6(...) must be both convertible to Foo. Are they? Let's find out. What's the overload of M2? There are a hundred possibilities. Let's see if each of them is convertible from the return type of M4 and M5... OK, we've tried all those, so we've found an M2 that works. Now what about M6? What if the "best" M2 we find is not compatible with the "best" M6? Should we backtrack and keep on re-trying all 100 x 100 possibilities until we find a compatible pair? The problem just gets worse and worse.

我们确实以这种方式对 lambda 进行推理,因此涉及 lambda 的重载解析在 C# 中至少是 NP-HARD.那很糟糕;我们宁愿不为编译器添加更多的 NP-HARD 问题来解决.

We do reason in this manner for lambdas and as a result overload resolution involving lambdas is at least NP-HARD in C#. That is bad right there; we would rather not add more NP-HARD problems for the compiler to solve.

您也可以在该语言的其他地方看到第一条规则.例如,如果你说: ILogger[] loggers = new[] { consoleLogger, suppressLogger }; 你会得到一个类似的错误;推断的数组元素类型必须是给定类型表达式的最佳类型.如果无法从中确定最佳类型,我们不会尝试找到您未提供给我们的类型.

You can see the first rule in action in other place in the language as well. For example, if you said: ILogger[] loggers = new[] { consoleLogger, suppressLogger }; you'd get a similar error; the inferred array element type must be the best type of the typed expressions given. If no best type can be determined from them, we don't try to find a type you did not give us.

类型推断也是如此.如果你说:

Same thing goes in type inference. If you said:

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

那么T就不会被推断为ILogger;这将是一个错误.T 被推断为提供的参数类型中最好的类型,并且其中没有最好的类型.

Then T would not be inferred to be ILogger; this would be an error. T is inferred to be the best type amongst the supplied argument types, and there is no best type amongst them.

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

For more details on how this design decision influences the behaviour of the conditional operator, see my series of articles on that topic.

如果您对为什么从外到内"起作用的重载解析是 NP-HARD 感兴趣,请参阅 这篇文章.

If you are interested in why overload resolution that works "from outside to inside" is NP-HARD, see this article.

这篇关于三元条件下的隐式转换问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆