2017-08-13 5 views
2

Ich versuche, eine fließend-Schnittstelle mit einer Sammlung, ähnlich wie dieses (vereinfachte) Beispiel bauen:Wie erstellt man eine Sequenz mit einer fließenden Schnittstelle?

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

Die beste Lösung, die ich mit add kommen kann() als:

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

Das scheint eine Menge Overhead hinzuzufügen, der bei jedem Anruf wiederholt wird.

Gibt es einen besseren Weg?

UPDATE: in meiner Eile habe ich das Beispiel zu stark vereinfacht und eine wichtige Anforderung weggelassen. Der letzte Eintrag in der vorhandenen Spalte beeinflusst den nächsten Eintrag. Also, ein etwas weniger vereinfachtes Beispiel:

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; 
} 
+0

Interessante Frage. Ich bin mir jedoch nicht sicher, ob es einen besseren Weg gibt, dies fließend zu machen. Sie könnten die 'Add'-Methode dazu bringen, ein' params'-Array zu verwenden und alle auf einmal hinzuzufügen, aber das beantwortet die Frage nicht wirklich. – DavidG

+0

Ich glaube nicht, dass es da ist. Außer wenn Sie eine interne Pufferung behalten, zum Beispiel mit 'ImmutableList ' oder etwas ähnliches. –

Antwort

1

Sie könnten wie folgt vorgehen:

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

Bitte beachte, dass ich IReadOnlyList bin mit ihm zu Index in die Liste in einer performanten Art und Weise möglich zu machen und seine kann das letzte Element bei Bedarf abrufen. Wenn du eine faule Aufzählung brauchst, dann denke ich, dass du bei deiner ursprünglichen Idee feststeckst.

Und sicher genug, die folgenden:

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

Erzeugt das erwartete Ergebnis ({1, 12, 123, 1234}) mit, was ich denke, ist, eine angemessene Leistung.

+0

Alle diese Methodenaufrufe geben nun alle denselben Verweis auf eine einzige änderbare (und mutierte) Datenstruktur zurück. Also, wenn Sie 'var start = Starts (1) schreiben; var nextValue = start.Times10Plus (2); Console.WriteLine (start.Count); 'es würde 2 und nicht 1 ausgeben, was falsch ist. – Servy

+0

@servy ja ich weiß, aber es ist nicht klar aus der Frage, ob dies unerwünscht ist oder nicht. Wie auch immer, das ist leicht zu reparieren, verwenden Sie einfach eine unveränderliche Warteschlange als den inneren Typ und das war's. Wenn das Enumerieren nicht leistungskritisch ist, können Sie sogar einen einfachen einfachen unveränderlichen Stapel verwenden, der in umgekehrter Reihenfolge aufzählt. – InBetween

+0

Mit anderen Worten, Sie sind jetzt wieder bei der Verwendung der OP-Lösung. – Servy

Verwandte Themen