在书呆子晚餐教程中有趣的使用C#产量关键字 [英] Interesting use of the C# yield keyword in Nerd Dinner tutorial

查看:163
本文介绍了在书呆子晚餐教程中有趣的使用C#产量关键字的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

 : -  

通过教程工作(专业ASP.NET MVC的书呆子晚餐),我碰到这个代码片段来了公共IEnumerable的< RuleViolation> GetRuleViolations(){
如果(String.IsNullOrEmpty(标题))
收益回报新RuleViolation(标题要求,标题);
如果(String.IsNullOrEmpty(描述))
收益回报(描述必需的,说明)新RuleViolation;
如果(String.IsNullOrEmpty(HostedBy))
收益回报新RuleViolation(需要HostedBy,HostedBy);
如果(String.IsNullOrEmpty(地址))
收益回报(地址需要,地址)的新RuleViolation;
如果(String.IsNullOrEmpty(国家))
收益回报新RuleViolation(国家需要,国家);
如果(String.IsNullOrEmpty(ContactPhone))
收益回报新RuleViolation(电话号码要求,ContactPhone);如果
(!PhoneValidator.IsValidNumber(ContactPhone,国家))
收益回报新RuleViolation(电话号码不符合国家,ContactPhone);
产量突破;
}



我在收益,但我想我的理解还是有点几分朦胧。什么,似乎做的是创造的对象允许的通过项目循环集合中没有实际的的循环,除非及直至它是绝对必要的。



这个例子是一个有点怪我,虽然。我觉得它做的是拖延任何 RuleViolation 实例的创建,直到程序员实际上集合中使用任何每个或类似 .ElementAt(2)



除此之外,虽然,我有一些问题:




  1. 在做的条件部分的如果声明得到评估?当 GetRuleViolations()被调用或当枚举实际上是重复?换句话说,如果标题变化的值真是令人讨厌的晚餐我打电话的时候 GetRuleViolations之间(),我试图其实遍历它的时候,就会 RuleViolation(所需的标题,标题)创建或不


  2. 为什么产量突破; 有必要吗?什么是不是真的在这里做什么?


  3. 比方说,标题为null或空。如果我称之为 GetRuleViolations()然后遍历一排,多少次会新RuleViolation(标题要求所产生的枚举两次。标题)被称为?



解决方案

包含收益率的函数命令比正常功能区别对待。这是怎么回事时,该功能被称为幕后,是一个匿名类型构造具体的的IEnumerable 函数的类型,函数创建该类型的对象,返回。匿名类包含执行相应的功能了的身体,直到下一个产量逻辑每一次命令 IEnumerable.MoveNext 被调用。这是一个有点误导,函数的身体不是在一个批处理执行像一个正常的功能,而是件,当枚举向前移动一步每件执行。



至于你的问题:




  1. 正如我所说的,每个如果得到当你迭代到下一个元素执行。

  2. 产量突破的确不是在上面的例子必要的。它所做的是它终止枚举。

  3. 每次遍历枚举时,又迫使代码的执行。把一个断点相关行和测试自己。


Working through a tutorial (Professional ASP.NET MVC - Nerd Dinner), I came across this snippet of code:

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;
}

I've read up on yield, but I guess my understanding is still a little bit hazy. What it seems to do is create an object that allows cycling through the items in a collection without actually doing the cycling unless and until it's absolutely necessary.

This example is a little strange to me, though. What I think it's doing is delaying the creation of any RuleViolation instances until the programmer actually requests a specific item in the collection using either for each or a LINQ extension method like .ElementAt(2).

Beyond this, though, I have some questions:

  1. When do the conditional parts of the if statements get evaluated? When GetRuleViolations() is called or when the enumerable is actually iterated? In other words, if the value of Title changes from null to Really Geeky Dinner between the time that I call GetRuleViolations() and the time I attempt to actually iterate over it, will RuleViolation("Title required", "Title") be created or not?

  2. Why is yield break; necessary? What is it really doing here?

  3. Let's say Title is null or empty. If I call GetRuleViolations() then iterate over the resulting enumerable two times in a row, how many times will new RuleViolation("Title required", "Title") be called?

解决方案

A function that contains yield commands is treated differently than a normal function. What is happening behind the scenes when that function is called, is that an anonymous type is constructed of the specific IEnumerable type of the function, the function creates an object of that type and returns it. The anonymous class contains logic that executes the body of the function up until the next yield command for every time the IEnumerable.MoveNext is called. It is a bit misleading, the body of the function is not executed in one batch like a normal function, but rather in pieces, each piece executes when the enumerator moves one step forward.

With regards to your questions:

  1. As I said, each if gets executed when you iterate to the next element.
  2. yield break is indeed not necessary in the example above. What it does is it terminates the enumeration.
  3. Each time you iterate over the enumerable, you force the execution of the code again. Put a breakpoint on the relevant line and test for yourself.

这篇关于在书呆子晚餐教程中有趣的使用C#产量关键字的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆