空条件运算符“取消”数组元素的存在

新的C#6.0空条件运算符是一种用于编写更简洁,不太复杂的代码的便捷工具。 假设有一个客户数组,那么如果customers使用此值(MSDN中的示例)为null,那么您可以得到null而不是长度:

int? length = customers?.Length;

同样,你可以用null来代替客户:

Customer first = customers?[0];

而对于更精细的表达式,如果customers为空,第一个客户为空或第一个客户的Orders对象为空,则此值为空:

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

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

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

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

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

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


不,因为它是一个空值条件运算符,而不是一个indexoutofrange -conditional运算符,并且仅仅是语法糖类,如下所示:

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

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

你可以看到,如果没有第零个客户,你会得到你经常发生的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();

没有零,没有问题。


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

例如:

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

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

链接地址: http://www.djcxy.com/p/13067.html

上一篇: Null conditional operator to "nullify" array element existence

下一篇: Is there any performance gain when using features from C# 6.0?