首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何创建带有可选操作的IEnumerable?

如何创建带有可选操作的IEnumerable?
EN

Stack Overflow用户
提问于 2014-08-19 11:42:17
回答 2查看 145关注 0票数 0

我有IntegerRectangle课。我希望它有一个internal_perimeter()方法,它返回其周长的所有点,而internal_perimeter(Action<Integer> processor)方法将processor应用到其周长的所有点。

我的一个类有一个变量IntegerRect canvas;HashSet<IntegerPoint> forbidden_points,它调用:

代码语言:javascript
复制
canvas.internal_perimeter((IntegerPoint p)=>{forbidden_points.Add(p); print("[f]" + forbidden_points.Contains(p).ToString());});

不同internal_perimeter()实现的结果不同

这样做是可行的:

代码语言:javascript
复制
public IEnumerable<IntegerPoint> internal_perimeter()
{
    for(int i=0;i<width;++i)
    {
        yield return new IntegerPoint(x+i,y);
    }
    for(int i=1;i<height;++i)
    {
        yield return new IntegerPoint(x+width-1,y-i);
    }
    for(int i=width-2;i>=0;--i)
    {
        yield return new IntegerPoint(x+i,y-height+1);
    }
    for(int i=height-2;i>=0;--i)
    {
        yield return new IntegerPoint(x,y-i);
    }
}
public void internal_perimeter(Action<IntegerPoint> processor)
{
    foreach(IntegerPoint i in internal_perimeter())
        processor(i);
}

这并不是:

代码语言:javascript
复制
public IEnumerable<IntegerPoint> internal_perimeter(Action<IntegerPoint> processor=null)
{
    if(processor==null)
    {
        for(int i=0;i<width;++i)
        {
            yield return new IntegerPoint(x+i,y);
        }
        for(int i=1;i<height;++i)
        {
            yield return new IntegerPoint(x+width-1,y-i);
        }
        for(int i=width-2;i>=0;--i)
        {
            yield return new IntegerPoint(x+i,y-height+1);
        }
        for(int i=height-2;i>=0;--i)
        {
            yield return new IntegerPoint(x,y-i);
        }
    }
    else
        foreach(IntegerPoint i in internal_perimeter())
            processor(i);
}

我不明白第二个怎么了

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2014-08-19 11:47:46

第二个例子是迭代器(它使用yield return)。在枚举它之前,不会执行这种函数。

如果你这么做了:var x = internal_perimeter(i => {});

变量x将保存由编译器从函数构造的类的IEnumerable<IntegerPoint>。您的代码目前还没有执行。

现在,尝试使用它:foreach(var point in x) {}。这将执行您的功能。实际上,在特定情况下,所有这些都将在第一次迭代中执行,因此调用x.FirstOrDefault();就足够了。实际上,在枚举数上调用MoveNext将执行代码直到第一个yield return,并且代码的else分支中没有任何代码。

现在,我想举你的第一个例子,因为这一点。它不太容易出错。

票数 2
EN

Stack Overflow用户

发布于 2014-08-19 12:01:39

要添加到@Lucas' answer中,这可以回答为什么您的代码不能工作,您还应该考虑重构您的代码:

  1. internal_perimeter是该方法的坏名称。如果它的目的是改变内部点,那么它应该被命名为void Process(Action a)或类似的东西。
  2. 第二个例子很成问题,因为当您不为action参数传递null时,它什么也不返回(空序列)。使用Func<T, Tresult (如LINQ )并返回所有处理过的参数将更有意义。而且,null分支非常少见(很少建议像这样传递null委托)。
  3. 接下来,这个方法确实做得太少了。为什么你需要一个新的方法,有一个现有的LINQ替代方案?即: var rect =新的IntegerRectangle();//这将得到一个点的列表var forbiddenPoints = rect.internal_perimeter().ToList();//这会过滤它们并将它们投影// (即“获取大于10的所有x坐标”) var xLargerThan10 = rect .internal_perimeter() .Where(p => p.X > 10) .Select(p => p.X) .ToList();
  4. 即使最初的internal_perimeter重载也可能有一个更好的名称,例如,简单地说,GetPoints可以很好地说明它的目的是什么: foreach (var point in rect.GetPoints()) DoStuff(point);
票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/25382524

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档