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



新的 C# 6.0 空条件运算符是编写更简洁、更少复杂的代码的便捷工具。假设有一个客户数组,那么如果customers是空的,则可以使用以下命令获得 null 而不是长度(MSDN 中的示例(:

int? length = customers?.Length;

同样,您可以通过以下方式获得 null 而不是客户:

Customer first = customers?[0];

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

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

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

在我看来,空条件运算符只专注于否定 NullReferenceException 的影响;IndexOutOfRangeException或KeyNotFoundException是孤独的,暴露的,畏缩在角落里,需要自生自灭!我认为,本着空条件运算符的精神,它也应该能够处理这些情况......这就引出了我的问题。

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

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

。当没有第零个元素时?

不,因为它是一个条件运算符,而不是索引范围条件运算符,并且只是类似以下内容的语法糖:

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();
customers?.FirstOrDefault()?.Orders?.Count();

没有零,没问题。

如果要在没有 NullReference 或 IndexOutOfRange 异常的情况下获取第 n 个元素,可以使用:

customers?.Skip(n)?.FirstOrDefault()

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

例如:

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 为空就会抛出的空引用异常。

如果我们要捕获索引查找异常、找不到键异常等,也会出现同样的错误捕获问题。

相关内容

  • 没有找到相关文章

最新更新