在Nerd晚餐教程中有趣地使用了C#yield关键字
通过教程(专业ASP.NET MVC - 书呆子晚餐),我遇到了这段代码:
public IEnumerable<RuleViolation> GetRuleViolations() {
if (String.IsNullOrEmpty(Title))
yield return new RuleViolation("Title required", "Title");
if (String.IsNullOrEmpty(Description))
yield return new RuleViolation("Description required","Description");
if (String.IsNullOrEmpty(HostedBy))
yield return new RuleViolation("HostedBy required", "HostedBy");
if (String.IsNullOrEmpty(Address))
yield return new RuleViolation("Address required", "Address");
if (String.IsNullOrEmpty(Country))
yield return new RuleViolation("Country required", "Country");
if (String.IsNullOrEmpty(ContactPhone))
yield return new RuleViolation("Phone# required", "ContactPhone");
if (!PhoneValidator.IsValidNumber(ContactPhone, Country))
yield return new RuleViolation("Phone# does not match country", "ContactPhone");
yield break;
}
我已经读过yield
,但我想我的理解还是有点朦胧。 看起来要做的是创建一个对象,该对象允许循环访问集合中的项目,而不必实际进行循环,除非并且直到绝对必要时为止。
不过,这个例子对我来说有点奇怪。 我认为它的做法是延迟创建任何RuleViolation
实例,直到程序员实际上使用for each
或者像.ElementAt(2)
这样的LINQ扩展方法请求集合中的特定项目。
除此之外,我还有一些问题:
何时对if
语句的条件部分进行评估? 何时GetRuleViolations()
或实际迭代枚举? 换句话说,如果在我调用GetRuleViolations()
的时间与尝试实际遍历它的时间之间, Title
的值从null
更改为Really Geeky Dinner
,那么将创建RuleViolation("Title required", "Title")
或不?
为什么yield break;
必要? 这里真的在做什么?
假设Title
为空或空白。 如果我调用GetRuleViolations()
然后遍历所产生的枚举两次new RuleViolation("Title required", "Title")
将调用new RuleViolation("Title required", "Title")
多少次?
包含yield
命令的函数与普通函数的处理方式不同。 调用该函数后面发生的事情是,匿名类型由特定的IEnumerable
类型的函数构造而成,该函数创建该类型的对象并将其返回。 匿名类包含执行函数主体的逻辑,直到每次调用IEnumerable.MoveNext
一个yield
命令为止。 这有点误导,函数的主体并不像一个普通的函数那样在一个批处理中执行,而是以枚举的形式执行,当枚举器向前移动一步时,每个部分都会执行。
关于你的问题:
if
都会被执行。 yield break
确实没有必要。 它所做的是终止枚举。 1)以这个更简单的例子:
public void Enumerate()
{
foreach (var item in EnumerateItems())
{
Console.WriteLine(item);
}
}
public IEnumerable<string> EnumerateItems()
{
yield return "item1";
yield return "item2";
yield break;
}
每次从IEnumerator
调用MoveNext()
,代码将从yield
点返回并移至下一个可执行的代码行。
2) yield break;
会告诉IEnumerator
,没有什么更多的枚举。
3)每次枚举一次。
使用yield break;
public IEnumerable<string> EnumerateUntilEmpty()
{
foreach (var name in nameList)
{
if (String.IsNullOrEmpty(name)) yield break;
yield return name;
}
}
简洁版本:
1:收益率是神奇的“停止并再次回来”关键字,因此评估了“活跃”之前的if语句。
2:yield break明确结束枚举(在switch case中认为是“break”)
3:每一次。 当然,您可以将结果缓存到列表中,然后迭代。
链接地址: http://www.djcxy.com/p/53775.html上一篇: Interesting use of the C# yield keyword in Nerd Dinner tutorial
下一篇: Is 'yield' keyword a syntactic sugar ? What is its Implementation