2

I was looking for, but could not find, an idiomatic example for a generic class implementing IEnumerable, which does this: constructor takes start and interval, and GetEnumerator returns IEnumerator, which starts from starts and goes on forever returning items with the interval.

In other words, something like:

public class Sequence<T> : IEnumerable<T> where T :... {

    public T start { get; private set; }
    public T interval { get; private set; }

    Sequence(T start, T interval) 
    {
        ...
    }

    IEnumerator<T> GetEnumerator() 
    {
        for(T n = start ; ; n += interval) // does not compile
            yield return n; 
    }

    ... what else?
}

There are lots of related questions, and small snippets, bits&pieces, but I have not been able to find a single nice example of a complete class, which does at least something similar enough. This is about how to implement this, so if there is existing class which does just this, it'd be good to know, but not an answer to the question.

So, actual question(s): Which is the most recent C# version that has introduced new features useful for this, and what is the ideal example code to do this with it?

Also if there are any common pitfalls, mistakes which inexperienced C# developers make related to this kind of a class, those would be good to know.


Update: since the exact thing I'm asking for seems impossible, I guess the next best thing is replacing interval with a lambda for getting the next item, or something like that.

4

3 回答 3

2

感谢 dlev 的建议Func,我最初只是使用一个辅助类。

public class Sequence<T> : IEnumerable<T>
{
  public T Start { get; private set; }
  public T Interval { get; private set; }
  private Func<T, T, T> Adder { get; set; }

  public Sequence(T start, T interval, Func<T,T,T> adder)
  {
    Start = start;
    Interval = interval;
    Adder = adder;
  }

  public IEnumerator<T> GetEnumerator()
  {
    for (T n = Start; ; n = Adder.Invoke(n, Interval))
      yield return n;
  }

  IEnumerator IEnumerable.GetEnumerator()
  {
    return this.GetEnumerator();
  }
}

然后你可以像这样使用它:

int i = 0;
foreach (int t in new Sequence<int>(3, 4, (int a, int b) => a + b))
{
    if (i == 10)
    {
        break;
    }
    i++;
    Console.WriteLine(t);
}

或者,您可以要求T实现某种Addable接口并调用该Add方法,但我认为这更干净。

于 2013-05-13T18:19:34.363 回答
2

您所描述的与MoreLinqGenerate的功能非常相似。

实现很简单:

public static IEnumerable<TResult> Generate<TResult>(TResult initial, Func<TResult, TResult> generator)
{
    if (generator == null) throw new ArgumentNullException("generator");
    return GenerateImpl(initial, generator);
}

private static IEnumerable<TResult> GenerateImpl<TResult>(TResult initial, Func<TResult, TResult> generator)
{
    TResult current = initial;
    while (true)
    {
        yield return current;
        current = generator(current);
    }
}
于 2013-05-13T19:27:16.570 回答
1

作为使用委托的替代方法,您可以使用MiscUtil 中的通用运算符。使用它,您的代码将如下所示:

IEnumerator<T> GetEnumerator() 
{
    for(T n = start ; ; n = Operator.Add(n, interval))
        yield return n; 
}
于 2013-05-13T19:22:56.420 回答