29

每次我需要在使用 C# 的算法中执行N次操作时,我都会编写这段代码

for (int i = 0; i < N; i++)
{
    ...
}

学习 Ruby 我了解了方法times()可以与这样的相同语义一起使用

N.times do
    ...
end

C# 中的代码片段看起来更复杂,我们应该声明无用的变量i

我尝试编写返回IEnumerable的扩展方法,但我对结果不满意,因为我必须再次声明一个循环变量i

public static class IntExtender
{
    public static IEnumerable Times(this int times)
    {
        for (int i = 0; i < times; i++)
            yield return true;
    }
}

...

foreach (var i in 5.Times())
{
    ...
}

是否可以使用一些新的 C# 3.0 语言特性让N次循环更优雅?

4

4 回答 4

51

cvk 回答的稍微简短的版本:

public static class Extensions
{
    public static void Times(this int count, Action action)
    {
        for (int i=0; i < count; i++)
        {
             action();
        }
    }

    public static void Times(this int count, Action<int> action)
    {
        for (int i=0; i < count; i++)
        {
             action(i);
        }
    }
}

采用:

5.Times(() => Console.WriteLine("Hi"));
5.Times(i => Console.WriteLine("Index: {0}", i));
于 2008-10-07T08:15:04.240 回答
14

C# 3.0 确实有可能:

public interface ILoopIterator
{
    void Do(Action action);
    void Do(Action<int> action);
}

private class LoopIterator : ILoopIterator
{
    private readonly int _start, _end;

    public LoopIterator(int count)
    {
        _start = 0;
        _end = count - 1;
    }

    public LoopIterator(int start, int end)
    {
        _start = start;
        _end = end;
    }  

    public void Do(Action action)
    {
        for (int i = _start; i <= _end; i++)
        {
            action();
        }
    }

    public void Do(Action<int> action)
    {
        for (int i = _start; i <= _end; i++)
        {
            action(i);
        }
    }
}

public static ILoopIterator Times(this int count)
{
    return new LoopIterator(count);
}

用法:

int sum = 0;
5.Times().Do( i => 
    sum += i
);

无耻地从http://grabbagoft.blogspot.com/2007/10/ruby-style-loops-in-c-30.html窃取

于 2008-10-07T08:09:51.923 回答
0

如果您使用的是 .NET 3.5,那么您可以使用本文中提出的每个扩展方法,并使用它来避免经典循环。

public static class IEnumerableExtensions
  {
      public static void Each<T>(
        this IEnumerable<T> source,
        Action<T> action)
      {
          foreach(T item in source)
          {
              action(item);
          }
      }
  }

这种特殊的扩展方法在任何实现 IEnumerable 的东西上点焊了 Each 方法。您知道这一点,因为此方法的第一个参数定义了 this 在方法主体中的内容。Action 是一个预定义的类,它基本上代表一个不返回值的函数(委托)。在方法内部,是从列表中提取元素的位置。这种方法使我能够在一行代码中干净地应用一个函数。

http://www.codeproject.com/KB/linq/linq-to-life.aspx

希望这可以帮助。

于 2008-10-07T08:12:18.753 回答
0

我编写了自己的扩展,将 Times 添加到 Integer(以及其他一些内容)。您可以在此处获取代码:https ://github.com/Razorclaw/Ext.NET

该代码与 Jon Skeet 的答案非常相似:

public static class IntegerExtension
{
    public static void Times(this int n, Action<int> action)
    {
        if (action == null) throw new ArgumentNullException("action");

        for (int i = 0; i < n; ++i)
        {
            action(i);
        }
    }
}
于 2013-04-12T15:59:44.407 回答