Есть ли шансы подражать методу times () Ruby в C #? - PullRequest
29 голосов
/ 07 октября 2008

Каждый раз, когда мне нужно что-то сделать N раз внутри алгоритма с использованием C #, я пишу этот код

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 ]

49 голосов
/ 07 октября 2008

Немного короткая версия ответа 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 голосов
/ 07 октября 2008

Это действительно возможно с 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 голосов
/ 12 апреля 2013

Я написал свое собственное расширение, которое добавляет Times к Integer (плюс некоторые другие вещи). Вы можете получить код здесь: https://github.com/Razorclaw/Ext.NET

Код очень похож на ответ Джона Скита:

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);
        }
    }
}
0 голосов
/ 07 октября 2008

Если вы используете .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 Ты знаешь это потому, что первый параметр этот метод определяет, что это будет внутри тела метода. Действие это заранее определенный класс, который в основном заменяет функцию (делегат) не возвращая значения. Внутри метода, где элементы извлекаются из списка. Что это за метод позволяет мне чисто применить функция в одной строке кода.

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

Надеюсь, это поможет.

...