有没有在C#中模仿Ruby的times()方法的机会?

29

每当我需要在算法中使用 C# 执行某个操作 N 次时,我都会编写以下代码:

Every time I need to do something N times inside an algorithm using C# I write this code


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个回答

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));

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不要脸地借鉴过来


0
如果您正在使用.NET 3.5,则可以使用本文中提供的扩展方法Each,并将其用于避免经典循环。
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)

希望这有所帮助。

0

我编写了自己的扩展,将时间添加到整数(以及其他一些内容)。您可以在此处获取代码: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);
        }
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接