if子句与yield结合使用 [英] If clause combined with yield
问题描述
我不经常使用收益,但遇到了一些我感到困惑的事情。
代码库有以下内容:
public IEnumerable < dynamic > 积分
{
get {
foreach(GetData中的var o)yield return o;
}
}
私有IEnumerable < 动态 > GetData()
{
if(Model.Plan == null ||
Model.Plan.Points == null ||
Model.Plan.Points.Datas == null)
{
yield return null;
}
foreach(Model.Plan.Points.Datas中的var数据)
{
收益率数据;
}
}
请不要挂断对象及其名称。这真的没关系。
我看到的行为是 Model.Plan.Points
是null ,但我在foreach循环中得到一个空引用,它引用了Points中的数据。不应该先前的条件不允许吗?
if(Model.Plan.Points == null)yield return null;
因为yield返回null;
使迭代器处于它认为有更多项的状态,foreach
循环积分
接下来转到foreach
循环,然后给出null引用异常。
所以如果null-check分支是,那么这个方法一定不能进入foreach
拍摄。
只需将foreach
放入else
条款中!
private IEnumerable< dynamic> GetData()
{
if (Model.Plan == null ||
Model.Plan.Points == null ||
Model.Plan.Points.Datas == null )
{
yield return 空跨度>;
}
其他
{
foreach (< span class =code-keyword> var data in Model.Plan.Points.Datas)
{
yield return 数据;
}
}
}
话虽如此,这可以大大简化,因为Model.Plan .Points.Datas
显然是IEnumerable< dynamic>
:
private IEnumerable< dynamic> GetData()
{
if (Model.Plan == null ||
Model.Plan.Points == null ||
Model.Plan.Points.Datas == null )
{
return Enumerable.Empty< dynamic>();
}
其他
{
返回模型。 Plan.Points.Datas; // 。如有必要,请展开< dynamic>()。
}
}
虽然yield return o
确实在这里返回null,但问题是你之后在做什么?基本上,yield return null
将null返回到Points
调用,并返回到上面的级别。你在这个调用中需要做的是将yield return o
包起来,这样它就不会yield
如果它得到null。像这样重写:public IEnumerable< dynamic>积分
{
获取
{
foreach ( var o GetData())
{
if (o!= null )
{
yield return o;
}
}
}
}现在你可以自信地打电话来知道你将获得没有空值的数据。
好的,我看到你现在遇到的问题。导致您出现问题的一点是误解了yield
实际上在这里做了什么。基本上,虽然它会向调用者返回一个值,但它仍然会在此方法中继续处理。它不像return语句那样,它只是将值返回给调用者。可能,使用yield语句,您可以在一次调用中出现多个值。
因此,下一个语句适用于Model.Plan.Points的事实可能因为Model.Plan或Model.Plan.Points为null而失败。您可以通过将该部分放在else子句中来解决这个问题。
这是一种真正让你的思想充满理智的方法 - 假设模型是完全填充:private IEnumerable< dynamic> GetData()
{
foreach ( var data in Model.Plan.Points)
{
yield return 数据;
}
foreach ( var 数据 in Model.Plan.Points)
{
yield return 数据;
}
}
我认为收益率回报
不退出方法。
也许:
if (Model.Plan == < span class =code-keyword> null ||
Model.Plan.Points == null ||
Model。 Plan.Points.Datas == null )
{
return 空跨度>;
}
// ...
I do not use yield often but have run into something that I am confused by.
A code base has the following:
public IEnumerable<dynamic> Points
{
get {
foreach (var o in GetData) yield return o;
}
}
private IEnumerable<dynamic> GetData()
{
if (Model.Plan == null ||
Model.Plan.Points == null ||
Model.Plan.Points.Datas== null)
{
yield return null;
}
foreach (var data in Model.Plan.Points.Datas)
{
yield return data;
}
}
Please don't get hung up on the objects and their names. It really shouldn't matter.
The behavior I am seeing is the Model.Plan.Points
is null, but I get a null reference in the foreach loop that is referencing the datas inside the Points. Shouldn't the previous conditional not allow that?
if(Model.Plan.Points == null) yield return null;
Because theyield return null;
leaves the iterator in a state where it believes there are more items, theforeach
loop inPoints
next goes to theforeach
loop here, which then gives the null reference exception.
So this method must not proceed to theforeach
if the null-check branch is taken.
Just put theforeach
in theelse
clause!
private IEnumerable<dynamic> GetData() { if (Model.Plan == null || Model.Plan.Points == null || Model.Plan.Points.Datas== null) { yield return null; } else { foreach (var data in Model.Plan.Points.Datas) { yield return data; } } }
That being said, this can be greatly simplified, sinceModel.Plan.Points.Datas
is obviously anIEnumerable<dynamic>
:
private IEnumerable<dynamic> GetData() { if (Model.Plan == null || Model.Plan.Points == null || Model.Plan.Points.Datas== null) { return Enumerable.Empty<dynamic>(); } else { return Model.Plan.Points.Datas; //.Cast<dynamic>() if necessary. } }
Whileyield return o
does return null here, the question is what are you doing with it afterwards? Basically, theyield return null
is sending null back up to thePoints
call and is returned back to the level above. What you need to do in this call is wrap theyield return o
up so that it doesn'tyield
if it gets null. Rewrite it like this:public IEnumerable<dynamic> Points { get { foreach (var o in GetData()) { if (o != null) { yield return o; } } } }Now you can call this confidently knowing that you will get data without null values outside.
Okay, I see the issue you are getting now. The point that's causing you a problem is a misunderstanding of whatyield
actually does here. Basically, while it yields a value back to the caller, it will still continue processing inside this method. It doesn't act like a return statement, it merely yields the value back to the caller. Potentially, with a yield statement, you could have multiple values coming out of one call.
So, the fact that the next statement works on Model.Plan.Points may fail because Model.Plan or Model.Plan.Points is null. You could work around this by putting that part in an else clause.
[Edit]Here's a way to really blow your mind with a yield - assume that the model is fully populated :private IEnumerable<dynamic> GetData() { foreach (var data in Model.Plan.Points) { yield return data; } foreach (var data in Model.Plan.Points) { yield return data; } }
I thinkyield return
does not exit from the method.
Maybe:
if (Model.Plan == null || Model.Plan.Points == null || Model.Plan.Points.Datas== null) { return null; } // ...
这篇关于if子句与yield结合使用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!