if子句与yield结合使用 [英] If clause combined with yield

查看:329
本文介绍了if子句与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 the yield return null; leaves the iterator in a state where it believes there are more items, the foreach loop in Points next goes to the foreach loop here, which then gives the null reference exception.
So this method must not proceed to the foreach if the null-check branch is taken.
Just put the foreach in the else 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, since Model.Plan.Points.Datas is obviously an IEnumerable<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.
    }
}


While yield return o does return null here, the question is what are you doing with it afterwards? Basically, the yield return null is sending null back up to the Points call and is returned back to the level above. What you need to do in this call is wrap the yield return o up so that it doesn't yield 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 what yield 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 think yield 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屋!

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