2016-05-25 7 views
2

Beispielcode:C# Reactive Extensions - Speicherverwaltung und die Distinct Operator

public static IObservable<Order> ObserveOrders(this IProxy proxy,IEqualityComparer<Order> distinctPerDayComparer) 
    { 
     return Observable.FromEvent<Order>(ev => proxy.OrderUpdated += ev,ev => proxy.OrderUpdated -= ev) 
        .Distinct(distinctPerDayComparer); 
    } 

    public class DistinctPerDayComparer : IEqualityComparer<Order> 
    { 
     public bool Equals(Order o1, Order o2) 
     { 
      if(o1.Id != o2.Id) 
       return false; 

      bool isSameDay = o1.Date.Day == o2.Date.Day; 
      return isSameDay; 
     }    

     public int GetHashCode(Order o) 
     { 
      return o.Id.GetHashCode(); 
     } 
    } 

public class Order 
{ 
    public int Id { get; set; } 
    public DateTime Date { get; set; } 
} 

Szenario:

Sequenz:

{id:1,D:'5/25/2016'}-{id:1,D:'5/25/2016'}-{id:2,D:'5/25/2016'}-{id:1 ,D:'5/26/2016'} 

Distinct Sequenz:

{id:1,D:'5/25/2016'}-{id:2,D:'5/25/2016'}-{id:1,D:'5/26/2016'} 

Es sei nun angenommen dass d Die Sequenz läuft lange, tatsächlich wird onComplete nie aufgerufen.

Wie verwaltet Rx es, so dass es nicht alle eindeutigen Elemente im Speicher zum Vergleich enthält?

Ich vermute, es hält etwas zurück Speicher für Elemente in seiner Pipeline. aber ich dachte immer, dass nachdem onNext mit dem nächsten Gegenstand aufgerufen wurde, dieser Gegenstand einfach entsorgt wird.

Noch, wenn es entsorgt, welche Elemente verwendet Rx für den EqualityComparer beim Aufruf des Distinct-Operators?

+0

Distinct wird weiterhin Werte sammeln, die verglichen werden sollen, bis die Sequenz abgeschlossen ist. Es ist wahrscheinlich nicht das Werkzeug, das Sie wollen, oder Sie müssen die Sequenz entweder mit Window, TakeUntil + Repeat abschließen. Dies wird davon abhängen, wenn es akzeptabel ist Ihre Sammlung von Gegenständen neu zu starten (vielleicht täglich?) –

+0

ich habe bereits, dass, wie in der Antwort unten vorgeschlagen. –

+0

@LeeCampbell Entschuldigung, es wurde in den Kommentaren unten diese Antwort vorgeschlagen. Ich werde seine Antwort bearbeiten, um das –

Antwort

2

Wenn Sie sich den Rx-Quellcode ansehen, werden Sie feststellen, dass distinct ein Hashset verwendet und die Werte darin speichert. Ihre Annahme, dass Artikel einfach entsorgt wird, ist nicht korrekt.

Wenn Ihre Bestellobjekte schwer sind, können Sie den Schlüsselselektor verwenden, und RX speichert diesen Wert nur im Hashset.

.Distinct(o => Tuple.Create(o.id, o.Date), distinctPerDayComparer); 

dann distinctPerDayComparer müssen

public class DistinctPerDayComparer : IEqualityComparer<Tuple<int, DateTime>> 
{ 
    public bool Equals(Tuple<int, DateTime> o1, Tuple<int, DateTime> o2) 
    { 
     if(o1.Item1 != o2.Item1) 
      return false; 

     bool isSameDay = o1.Item2.Day == o2.Item2.Day; 
     return isSameDay; 
    }    

    public int GetHashCode(Tuple<int, DateTime> o) 
    { 
     return o.Item1.GetHashCode(); 
    } 
} 

geändert werden nicht den Code testen, sollte aber einen Startplatz sein. Speichert nun Tupel, bis die Sequenz abgeschlossen ist, anstelle Ihrer Auftragsobjekte.

Andernfalls könnten Sie die Fensterfunktion zu gruppieren sie verwenden und reinigen Sie sie auf einem Zeitplan, aber es ist dann nicht wirklich verschieden für die gesamte beobachtbare Folge.

+0

Dank zu enthalten. habe das nicht bemerkt. der Moderator ist infektiös. Ich frage mich, ob es einen Weg gibt, alle Elemente in der Reihenfolge jeden Tag zu entsorgen. –

+0

auf einen zweiten Blick auf meinen Code sehe ich, dass ich nur die 0 für das vereinfachte Beispiel oben geschrieben. Ich habe den Hashcode zurückgegeben. Ich habe die Frage bearbeitet. –

+2

Sie könnten das Fenster verwenden, um es einen pro day.Observable.FromEvent (ev => proxy.OrderUpdated + = ev, ev => proxy.OrderUpdated - = ev). .Window (TimeSpan.FromDays (1)) Wählen Sie (beobachtbar => observable.Distinct (distinctPerDayComparer)). Merge(); – CharlesNRice