And*_*ose 21 c# compiler-errors implicit-conversion
可能重复:
条件运算符无法隐式转换?
为什么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();
}
Run Code Online (Sandbox Code Playgroud)
如果我明确地将第一个conditioin强制转换为我的界面,这是有效的:
ILogger logger = suppressLogging ? ((ILogger)new SuppressLogger()) : new ConsoleLogger();
Run Code Online (Sandbox Code Playgroud)
显然我总能做到这一点:
ILogger logger;
if (suppressLogging)
{
logger = new SuppressLogger();
}
else
{
logger = new ConsoleLogger();
}
Run Code Online (Sandbox Code Playgroud)
替代方案很好,但我不能完全理解为什么第一个选项因隐式转换错误而失败,因为在我看来,这两个类都是ILogger类型,我不是真的想要进行转换(隐式或显式) ).我敢肯定这可能是一个静态语言编译问题,但我想了解发生了什么.
Eri*_*ert 38
这是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() ) );
Run Code Online (Sandbox Code Playgroud)
假设M1,M2和M6各有一百个重载.你是做什么?你说,好吧,如果这是M1(Foo)那么M2(...)和M6(......)必须都可以转换为Foo.是吗?我们来看看.什么是M2的超载?有一百种可能性.让我们看看它们中的每一个是否可以从M4和M5的返回类型转换......好吧,我们已经尝试了所有这些,所以我们发现了一个有效的M2.那么M6呢?如果我们找到的"最佳"M2与"最佳"M6不兼容怎么办?我们是否应该回溯并继续重新尝试所有100 x 100种可能性,直到找到兼容的对?问题变得越来越糟.
我们以这种方式对lambdas 进行推理,因此涉及lambda的重载决策在C#中至少是NP-HARD.那里那很糟糕; 我们宁愿不为编译器添加更多NP-HARD问题来解决.
您也可以在该语言的其他位置查看第一条规则.例如,如果你说: ILogger[] loggers = new[] { consoleLogger, suppressLogger };你会得到类似的错误; 推断的数组元素类型必须是给定的类型表达式的最佳类型.如果没有最佳类型可以确定,我们不会尝试找到您没有给我们的类型.
类型推断也是如此.如果你说:
void M<T>(T t1, T t2) { ... }
...
M(consoleLogger, suppressLogger);
Run Code Online (Sandbox Code Playgroud)
那么T不会被推断为ILogger; 这将是一个错误.T被推断为所提供的参数类型中的最佳类型,并且其中没有最佳类型.
有关此设计决策如何影响条件运算符行为的更多详细信息,请参阅我关于该主题的系列文章.
如果您对为什么"从外到内"工作的重载分辨率为NP-HARD感兴趣,请参阅此文章.
Tho*_*que 11
你可以这样做:
ILogger logger = suppressLogging ? (ILogger)(new SuppressLogger()) : (ILogger)(new ConsoleLogger());
Run Code Online (Sandbox Code Playgroud)
当你有一个类似的表达式时condition ? a : b,必须有从类型a到类型的隐式转换b,或者反过来,否则编译器无法确定表达式的类型.在你的情况下,SuppressLogger和之间没有转换ConsoleLogger...
(有关详细信息,请参阅C#4语言规范中的第7.14节)
| 归档时间: |
|
| 查看次数: |
3139 次 |
| 最近记录: |