简体   繁体   English

使用C#7的foreach声明中的空合并运算符

[英]Null-coalescing operator in a foreach declaration using C#7

I was looking at this code example in C# 7.0 and I was not sure about what was going on under the hood and the performance of this loop. 我在C# 7.0中查看这个代码示例,我不确定引擎盖下发生了什么以及此循环的性能。

foreach (var c in text ?? throw new ArgumentNullException(nameof(text)))
{
    ...
}

My questions: 我的问题:

  1. Does the conditional statement get hit once or multiple times (on each iteration)? 条件语句是一次还是多次(每次迭代)?
  2. The new syntax looks different, what are the benefits to doing it this way? 新语法看起来不同,这样做有什么好处?

In terms of "how foreach works", conditional statement will only be calculated once. 就“foreach如何运作”而言,条件陈述只计算一次。

You may want to read more about how foreach loops work in these questions: 您可能想要阅读有关foreach循环如何在这些问题中工作的更多信息:
How do foreach loops work in C#? foreach循环如何在C#中工作?
Does foreach evaluate the array at every iteration? foreach是否在每次迭代时评估数组?

Thanks to Svek for explaining that it is a new C# 7.0 feature, which will be released after Visual Studio 2017 RC: 感谢Svek解释这是一个新的C#7.0功能,它将在Visual Studio 2017 RC之后发布:
http://structuredsight.com/2016/09/01/c-7-additions-throw-expressions/ http://structuredsight.com/2016/09/01/c-7-additions-throw-expressions/

I think that "what are benefits" is a sort of opinion-based question. 我认为“什么是好处”是一种基于意见的问题。
In my opinion, it brings nothing good and is just ugly in terms or code readability. 在我看来,它没有带来什么好处,只是在术语或代码可读性方面是丑陋的。
I would recommend using a widely-used common good practice: 我建议使用广泛使用的常见良好做法:

if (text == null) // or string.IsNullOrEmpty for strings
    throw new ArgumentNullException(nameof(text));

foreach (var c in text)
{
    // ...
}

Probably, we will see null-coalescing + throw exception usage in a couple years and it will become a new standard :) 可能,我们将在几年内看到null-coalescing + throw异常使用,它将成为一个新标准:)

You should understand foreach inner code for understanding this C# feature. 您应该了解foreach内部代码以了解此C#功能。 A right part of expression in foreach statement must implement IEnumerable(<T>) interface, and whole loop is, internally, a simple while , something like this: foreach语句中表达式的右边部分必须实现IEnumerable(<T>)接口,整个循环在内部是一个简单的while ,类似这样的东西:

// here can be NullReferenceException
var en = text.GetEnumerator();
while(en.MoveNext())
{
    var c = en.Current;
    {
        ...
    }
}

As you can see, there is a point in this code the NRE can occur, so you need to check the enumerable before entire loop or Enumerable extensions class , like this: 正如您所看到的,此代码中有一点可以发生NRE ,因此您需要整个循环或Enumerable扩展类 之前检查枚举,如下所示:

if (text.IsNullOrWhitespace())
{
    throw new ArgumentNullException(nameof(text));
}

// while loop here or text.SomeLinqCodeHere()

There are some lines of code here which aren't really unnecessary, adding some entropy without real value. 这里有一些代码行并不是真的没必要,添加一些没有实际价值的熵。 In case of simple foreach it really opinion-based decision about code standards, but the real purpose of this feature is chaining it with other new things in C#7 , like ?. 在简单的foreach情况下,它确实是基于意见的关于代码标准的决定,但是这个功能的真正目的是将它与C#7其他新东西联系起来,比如?. operator , like this: 运营商 ,像这样:

int? length = customers?.Length ?? throw new ...;
Customer first = customers?[0] ?? throw new ...;  
int? count = customers?[0]?.Orders?.Count() ?? throw new ...;

In such cases throwing the exception is similar to comment at the end of the line of code: 在这种情况下抛出异常类似于代码行末尾的注释:

int? length = customers?.Length; // should not be null
Customer first = customers?[0]; // should not be null  
int? count = customers?[0]?.Orders?.Count(); // should not be null

but it adds some strict contract-like rules for your code. 但它为您的代码添加了一些严格的类似合同的规则。

As for the performance for foreach loop with such expressions, as already said, it doesn't suffer as getting the enumerator occurs only once, and before the real loop. 至于具有这种表达式的foreach循环的性能,正如已经说过的那样,它不会受到影响,因为枚举器只出现一次,并且真正的循环之前

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM