空条件运算符" nullify"数组元素存在

时间:2016-05-05 00:31:25

标签: c# arrays null c#-6.0 null-propagation-operator

新的C#6.0空条件运算符是编写更简洁,更少复杂代码的便捷工具。假设有一个客户数组,那么如果customers为空,那么你可以得到null而不是长度(来自MSDN的例子):

int? length = customers?.Length;

同样,您可以使用以下内容获取null而不是客户:

Customer first = customers?[0];

对于更精细的表达式,如果customers为空,第一个客户为空,或者第一个客户的Orders对象为空,则会产生null:

int? count = customers?[0]?.Orders?.Count();

但是有一个有趣的情况是不存在的客户,因为空条件运算符似乎没有解决。我们在上面看到, null 客户被覆盖,即customers数组中的条目为空。但这与不存在的客户完全不同,例如在3元素数组中查找客户5或在0元素列表中查找客户n。 (请注意,同样的讨论也适用于字典查找。)

在我看来,零条件运算符专注于否定NullReferenceException的影响; IndexOutOfRangeException或KeyNotFoundException独自暴露,在角落里畏缩,需要自生自灭!我提出,在零条件运算符的精神下,它应该能够处理这些情况......这导致了我的问题。

我错过了吗? null条件是否提供了真正涵盖此表达式的任何优雅方式......

customers?[0]?.Orders?.Count();

......当没有第0个元素时?

4 个答案:

答案 0 :(得分:23)

不,因为它是 null - 条件运算符,而不是 indexoutofrange - 条件运算符,并且仅仅是语法糖,如下所示:

int? count = customers?[0]?.Orders?.Count();

if (customers != null && customers[0] != null && customers[0].Orders != null)
{
    int count = customers[0].Orders.Count();
}

您可以看到,如果没有第0个客户,您将获得常规IndexOutOfRangeException

解决这个问题的一种方法是使用一个检查索引的扩展方法,如果它不存在则返回null:

public static Customer? GetCustomer(this List<Customer> customers, int index)
{
    return customers.ElementAtOrDefault(index); // using System.Linq
}

然后你的支票可能是:

int? count = customers?.GetCustomer(0)?.Orders?.Count();

答案 1 :(得分:8)

customers?.FirstOrDefault()?.Orders?.Count();

没有零,没有问题。

答案 2 :(得分:3)

它不支持索引安全性,因为当你开始使用它时,索引器实际上只是任何其他类型方法的语法糖。

例如:

public class MyBadArray
{
    public Customer this[int a]
    {
        get
        {
            throw new OutOfMemoryException();
        }
    }
}

var customers = new MyBadArray(); 
int? count = customers?[5]?.Orders?.Count();

这应该被抓到吗?如果异常更明智,类似于KeyNotFoundException,但特定于我们正在实施的集合类型,该怎么办?我们必须不断更新?.功能才能跟上。

此外,?.不会捕获异常。它阻止了他们。

var customer = customers?[5];实际编译为:

Customer customer = null;
if (customers != null)
    customer = customers[5];

让它捕获异常变得异常困难。例如:

void Main()
{
    var thing = new MyBadThing(); 
    thing.GetBoss()?.FireSomeone();
}

public class MyBadThing
{
    public class Boss
    {
        public void FireSomeone() 
        { 
            throw new NullReferenceException();
        }
    }
    public Boss GetBoss()
    {
        return new Boss();
    }
}

如果它只是捕获异常,它将被写为:

Boss boss = customer.GetBoss();
try 
{
    boss.FireSomeone();
} catch (NullReferenceException ex) { 

}

哪个实际上会捕获FireSomeone内的异常,而不是如果boss为null则抛出的null引用异常。

如果我们要捕获索引查找异常,关键未找到异常等,那么会出现同样的问题。

答案 3 :(得分:0)

如果要获取第n个元素而没有NullReference或IndexOutOfRange异常,则可以使用:

customers?.Skip(n)?.FirstOrDefault()
相关问题