编程语言
首页 > 编程语言> > c# – 如何使用流畅的界面构建序列?

c# – 如何使用流畅的界面构建序列?

作者:互联网

我正在尝试使用流畅的界面来构建集合,类似于此(简化)示例:

   var a = StartWith(1).Add(2).Add(3).Add(4).ToArray();
   /* a = int[] {1,2,3,4};  */

我能想出的最佳解决方案是将Add()添加为:

  IEnumerable<T> Add<T>(this IEnumerable<T> coll, T item)
  {
     foreach(var t in coll) yield return t;
     yield return item;
  }

这似乎增加了很多在每次调用中重复的开销.

有没有更好的办法?

更新:
在我的匆忙中,我过度简化了这个例子,并遗漏了一个重要的要求.现有coll中的最后一项影响下一项.所以,一个稍微简化的例子:

   var a = StartWith(1).Times10Plus(2).Times10Plus(3).Times10Plus(4).ToArray();
   /* a = int[] {1,12,123,1234};  */

public static IEnumerable<T> StartWith<T>(T x)
{
    yield return x;
}

static public  IEnumerable<int> Times10Plus(this IEnumerable<int> coll, int item)
{
    int last = 0;
    foreach (var t in coll)
    {
        last = t;
        yield return t;
    }
    yield return last * 10 + item;
}

解决方法:

您可以执行以下操作:

public static class MySequenceExtensions
{
    public static IReadOnlyList<int> Times10Plus(
        this IReadOnlyList<int> sequence, 
        int value) => Add(sequence, 
                          value,
                          v => sequence[sequence.Count - 1] * 10 + v);

    public static IReadOnlyList<T> Starts<T>(this T first)
        => new MySequence<T>(first);

    public static IReadOnlyList<T> Add<T>(
        this IReadOnlyList<T> sequence,
        T item,
        Func<T, T> func)
    {
        var mySequence = sequence as MySequence<T> ?? 
                         new MySequence<T>(sequence);
        return mySequence.AddItem(item, func);
    }

    private class MySequence<T>: IReadOnlyList<T>
    {
        private readonly List<T> innerList;

        public MySequence(T item)
        {
            innerList = new List<T>();
            innerList.Add(item);
        }

        public MySequence(IEnumerable<T> items)
        {
            innerList = new List<T>(items);
        }

        public T this[int index] => innerList[index];
        public int Count => innerList.Count;

        public MySequence<T> AddItem(T item, Func<T, T> func)
        {
            Debug.Assert(innerList.Count > 0);
            innerList.Add(func(item));
            return this;
        }

        public IEnumerator<T> GetEnumerator() => innerList.GetEnumerator();
        IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
    }
}

请注意,我正在使用IReadOnlyList使其能够以高效的方式索引到列表中,并且能够在需要时获取最后一个元素.如果你需要一个懒惰的枚举,那么我认为你坚持你最初的想法.

果然,以下内容:

var a = 1.Starts().Times10Plus(2).Times10Plus(3).Times10Plus(4).ToArray();

产生预期的结果({1,12,123,1234}),我认为是合理的表现.

标签:c,algorithm,net,linq,fluent-interface
来源: https://codeday.me/bug/20190627/1306476.html