在书呆子晚餐教程中有趣的使用C#产量关键字 [英] Interesting use of the C# yield keyword in Nerd Dinner tutorial
问题描述
: - 通过教程工作(专业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);
产量突破;
}
我在收益$读了C $ C>,但我想我的理解还是有点几分朦胧。什么,似乎做的是创造的对象允许的通过项目循环集合中没有实际的做的循环,除非及直至它是绝对必要的。
这个例子是一个有点怪我,虽然。我觉得它做的是拖延任何 RuleViolation
实例的创建,直到程序员实际上集合中使用任何每个$请求特定项目C $ C>或类似
.ElementAt(2)
。
除此之外,虽然,我有一些问题:
-
在做的条件部分的
如果
声明得到评估?当GetRuleViolations()
被调用或当枚举实际上是重复?换句话说,如果标题
从空
变化的值真是令人讨厌的晚餐
我打电话的时候GetRuleViolations之间()
,我试图其实遍历它的时候,就会RuleViolation(所需的标题,标题)
创建或不 -
为什么
产量突破;
有必要吗?什么是不是真的在这里做什么? -
比方说,
标题
为null或空。如果我称之为GetRuleViolations()
然后遍历一排,多少次会新RuleViolation(标题要求所产生的枚举两次。标题)
被称为?
包含收益率的函数
命令比正常功能区别对待。这是怎么回事时,该功能被称为幕后,是一个匿名类型构造具体的的IEnumerable
函数的类型,函数创建该类型的对象,返回。匿名类包含执行相应的功能了的身体,直到下一个产量逻辑
每一次命令 IEnumerable.MoveNext
被调用。这是一个有点误导,函数的身体不是在一个批处理执行像一个正常的功能,而是件,当枚举向前移动一步每件执行。
至于你的问题:
- 正如我所说的,每个
如果
得到当你迭代到下一个元素执行。 -
产量突破
的确不是在上面的例子必要的。它所做的是它终止枚举。 - 每次遍历枚举时,又迫使代码的执行。把一个断点相关行和测试自己。
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:
When do the conditional parts of the
if
statements get evaluated? WhenGetRuleViolations()
is called or when the enumerable is actually iterated? In other words, if the value ofTitle
changes fromnull
toReally Geeky Dinner
between the time that I callGetRuleViolations()
and the time I attempt to actually iterate over it, willRuleViolation("Title required", "Title")
be created or not?Why is
yield break;
necessary? What is it really doing here?Let's say
Title
is null or empty. If I callGetRuleViolations()
then iterate over the resulting enumerable two times in a row, how many times willnew 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:
- As I said, each
if
gets executed when you iterate to the next element. yield break
is indeed not necessary in the example above. What it does is it terminates the enumeration.- 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屋!