我有IntegerRectangle
课程。我希望它有internal_perimeter()
方法返回其周边的所有点,并internal_perimeter(Action<Integer> processor)
将processor
应用于其周边的所有点。
我的一个类有一个变量IntegerRect canvas;
和HashSet<IntegerPoint> forbidden_points
它调用:
canvas.internal_perimeter((IntegerPoint p)=>{forbidden_points.Add(p); print("[f]" + forbidden_points.Contains(p).ToString());});
internal_perimeter()
这有效:
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);
}
这不是:
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);
}
我不明白第二个出了什么问题
答案 0 :(得分:3)
要添加到@Lucas' answer,这解释了为什么您的代码不起作用,您还应该考虑重构代码:
internal_perimeter
是该方法的错误名称。如果它的目的是改变内部点,那么它应该被命名为void Process(Action a)
或类似的东西。
第二个示例相当有问题,因为当您没有为action参数传递null
时,它会返回 nothing (空序列)。使用Func<T, Tresult
(如LINQ Select)和yield返回所有已处理的参数会更有意义。此外,null
分支实际上并不常见(很少建议像这样传递null
代理。)
接下来,该方法确实做得太少了。为什么需要一个具有现有LINQ替代方案的新方法?即:
var rect = new IntegerRectangle();
// this gets a list of points
var forbiddenPoints = rect.internal_perimeter().ToList();
// this filters them and projects them
// (i.e. "get all x coordinates larger then 10")
var xLargerThan10 = rect
.internal_perimeter()
.Where(p => p.X > 10)
.Select(p => p.X)
.ToList();
即使原始的internal_perimeter
重载也可能有更好的名称,例如只需GetPoints
就可以说明它的目的是什么:
foreach (var point in rect.GetPoints())
DoStuff(point);
答案 1 :(得分:2)
你的第二个例子是迭代器(即它使用yield return
)。在枚举之前不会执行此类函数。
如果你这样做:var x = internal_perimeter(i => {});
变量x
将保存编译器从您的函数构造的类的IEnumerable<IntegerPoint>
。此时您的代码尚未执行。
现在,尝试使用它:foreach(var point in x) {}
。这将执行您的功能。实际上在你的特定情况下,它将在第一次迭代时执行,因此调用x.FirstOrDefault();
就足够了。实际上,在枚举器上调用MoveNext
将执行代码直到第一个yield return
,并且代码的else
分支中没有。
现在,因为这个原因,我会用你的第一个例子。它不易出错。