三元算子和协变强制

时间:2014-11-14 16:46:57

标签: c#

我宣布变量

IList<int> list;

然后我写了声明,

if(true)
{
    list = new List<int>();
}
else
{
    list = new int[0];
}

我有琐碎无意义的代码,可以在没有警告的情况下进行编译。如果我写声明,

list = true ? new List<int>() : new int[0];

我收到编译器警告,

  

'System.Collections.Generic.List&lt; int&gt;'之间没有隐式转换和'int []'

为什么三元运算符有此限制? List<int>int[]都实现了IList<int>


发布答案

来自C#5.0规范的 7.14条件运算符

  

?:运算符的第二个和第三个操作数x和y控制条件表达式的类型。

  1. 如果x的类型为X且y的类型为Y,则

    • 如果从X到Y存在隐式转换(第6.1节),而不是从Y到X,则Y是条件表达式的类型。

    • 如果从Y到X存在隐式转换(第6.1节),而不是从X到Y,则X是条件表达式的类型。

    • 否则,无法确定表达式类型,并发生编译时错误。

  2. 如果x和y中只有一个具有类型,并且x和y都可以隐式转换为该类型,那么这就是条件表达式的类型。

  3. 否则,无法确定表达式类型,并发生编译时错误。

2 个答案:

答案 0 :(得分:6)

list的分配不是问题。这是表达式true ? new List<int>() : new int[0]的问题。在任何情况下,这种表达都是不合法的。

如果您参考documentation,您会找到此信息。

  

first_expression和second_expression的类型必须相同,或者从一种类型到另一种类型必须存在隐式转换。

在这种情况下,情况并非如此。

答案 1 :(得分:2)

List<int>int[]都实现了很多内容(IEnumerable<int>IReadOnlyCollection<int>等。编译器很难在不给出提示的情况下知道你的意思:

list = true ? (IList<int>) new List<int>() : new int[0];

请记住,表达式是从里到外进行评估的。因此,在编译器查看您尝试将其分配给的内容之前,将对您的三元运算符进行求值。因此,必须存在某种隐式转换,从一侧的类型到另一侧的类型。

在您的if / else示例中,您有效地将List<int>转换为IList<int>作为自己的操作,而不是先尝试将其与int[]合并。