C#/ .NET 3.5中的强制转换如何适用于带有'?'的类型

时间:2010-06-09 15:53:31

标签: c# linq

  

可能重复:
  Nullable types and the ternary operator. Why won’t this work?

这是我的代码

public decimal? Get()
{
    var res = ...
    return res.Count() > 0 ? res.First() : (decimal?) null;
}

而且这个不起作用

public decimal? Get()
{
    var res = ...
    return res.Count() > 0 ? res.First() : null;
}

给出编译器错误:

  

错误1无法确定条件表达式的类型,因为'decimal'和'<null>'之间没有隐式转换

我想知道为什么?任何想法?

5 个答案:

答案 0 :(得分:7)

此行为在C#语言规范的第7.13节中介绍。

简而言之,三元运算符中两个表达式的类型必须是* * *,以便编译器确定三元表达式的类型。在这种情况下,正在考虑的两种类型是

  1. decimal
  2. null
  3. decimal类型是值类型,因此null不可转换为它。值null没有关联类型。这可以防止编译器确定表达式的类型并导致编译错误。

    在第一个示例中,第二个类型是decimal?decimaldecimal?之间存在转换,因此编译器会选择decimal?作为类型。

答案 1 :(得分:2)

错误很清楚。这俩 ”?” en“:”该条件运算符的部分需要具有相同的类型,或者必须至少隐式​​转换为相同的Type。单独的null没有良好的类型。

也许你可以使用.FirstOrDefault()。取决于resnull的{​​{1}}类型。

答案 2 :(得分:2)

偏离主题,但......

当你需要知道的是序列是否有任何元素时,使用Count是没有意义的。 Count会遍历所有元素,而Any会在遇到第一个元素后立即停止:

public decimal? Get()
{
    var res = ...
    return res.Any() ? res.First() : (decimal?)null;
}

或许这个:

public decimal? Get()
{
    var res = ...
    using (var e = res.GetEnumerator())
    {
        return e.MoveNext() ? e.Current : (decimal?)null;
    }
}

答案 3 :(得分:1)

我猜res是一个十进制数组,即decimal []。这是因为你已经声明了这样的res:

var res = { 1.0, 2.0, 3.0 };

而不是这样:

var res = { 1.0, 2.0, null };

所以编译器没有理由认为res是一个可以为空的小数组数组。

现在您正在使用三元运算符,它必须始终从两侧返回相同(或等效的可浇注)类型。

但是因为res.First()是'decimal'而且你的null默认是无类型的,它只会使你的null等同于你的第一个参数的类型(res.First(),即十进制)。通过强制将null键入为可空的十进制('decimal?'),您实际上是强制编译器将res.First()视为可以为空的十进制数。

然而,总体上更适合您的解决方案是:

public decimal? Get()
{
    decimal?[] res = ...
    return res.FirstOrDefault();
}

答案 4 :(得分:0)

在第二种情况下,您可以使用res.FirstOrDefault()

IEnumerable<T>.FirstOrDefault()在集合中返回第一个T,如果设置为空则返回default<T>null表示类和结构的一些默认值,通常情况下为{{1} }。

0

等于

public decimal? Get()
{
    var res = ...
    return res.FirstOrDefault();
}