Frage Ist ein Thema in RX.Net immer schädlich?


Ich habe mit einem Kollegen gesprochen, der mich auf die SO-Frage angesprochen hat Themen, die als schädlich angesehen werden. Ich habe jedoch zwei Fälle, in denen ich einen nicht-deterministischen Code habe, der auf andere Weise nicht vernünftig erscheint.

Nicht-Standard Veranstaltung:

 event handler(class, result)
 {
   subject.OnNext(result);
 }

 public delegate void _handler
   ([MarshalAs(UnmanagedType.Interface), In] MyClass class, 
    [MarshalAs(UnmanagedType.Interface), In] ResultClass result)

Parallele Aufgaben (Nicht-deterministische Anzahl von Tasks, die alle parallel laufen und zu unterschiedlichen Zeiten starten):

 Task.Start(()=> ...).ContinueWith(prevTask => subject.OnNext(prevTask.result))

Das Subjekt wird nicht bloß durch ein Observables exponiert. Gibt es einen anderen vorgeschlagenen Weg, der nicht eine Tonne Standardplatte ist?


9
2018-05-26 03:22


Ursprung


Antworten:


Themen sind nicht immer schädlich. Es gibt viele legitime Anwendungen von ihnen sogar innerhalb von Rx selbst. Jedoch oft, wenn eine Person ein Subjekt verwendet, gibt es bereits eine robuste Rx-Methode für dieses Szenario geschrieben (und es möglicherweise intern verwendet werden oder nicht). Dies ist der Fall für Ihre 2 Beispiele. Sehen Sie sich Task.ToObservable und Observable.FromEventPattern an.

Ein weiterer häufiger Fall, in dem Themen missbraucht werden, ist, wenn ein Entwickler einen Stream in zwei Teile aufteilt. Sie sind überzeugt, dass sie einen Stream abonnieren müssen, und im Callback produzieren sie Daten für einen neuen Stream. Sie machen das mit einem Subjekt. Aber normalerweise sollten sie stattdessen Select verwendet haben.


6
2018-05-26 23:52



Beobachtbar. Von Ereignis

System.FromEvent funktioniert für mehr als nur integrierte Ereignistypen: Sie müssen nur die richtige Überladung verwenden.

class Program
{
    private static event Action<int> MyEvent;

    public static void Main(string[] args)
    {
        Observable.FromEvent<int>(
            (handler) => Program.MyEvent += handler,
            (handler) => Program.MyEvent -= handler
            )
            .Subscribe(Console.WriteLine);

        Program.MyEvent(5);

        Console.ReadLine();
    }
}

Task.ToObservable & Zusammenführen

Wenn Sie bereits Zugriff auf alle Ihre Aufgaben haben, können Sie sie in Observables konvertieren und zu einer einzigen Observablen zusammenführen.

class Program
{
    public static void Main(string[] args)
    {
        Observable.Merge(
                // Async / Await
                (
                    (Func<Task<string>>)
                    (async () => { await Task.Delay(250); return "async await"; })
                )().ToObservable(),
                // FromResult
                Task.FromResult("FromResult").ToObservable(),
                // Run
                Task.Run(() => "Run").ToObservable()
            )
            .Subscribe(Console.WriteLine);

        Console.ReadLine();
    }
}

Beobachtbare zusammenführen

Alternativ können Sie, wenn Sie nicht alle Ihre Aufgaben im Voraus haben, Merge verwenden, aber Sie benötigen eine Möglichkeit, zukünftige Aufgaben zu kommunizieren. In diesem Fall habe ich ein Thema verwendet, aber Sie sollten das einfachste Observable verwenden, um dies auszudrücken. Wenn das ein Thema ist, dann verwenden Sie auf jeden Fall ein Thema.

class Program
{
    public static void Main(string[] args)
    {
        // We use a subject here since we don't have all of the tasks yet.
        var tasks = new Subject<Task<string>>();

        // Make up some tasks.
        var fromResult = Task.FromResult("FromResult");
        var run = Task.Run(() => "Run");
        Func<Task<string>> asyncAwait = async () => {
            await Task.Delay(250);
            return "async await";
        };

        // Merge any future Tasks into an observable, and subscribe.
        tasks.Merge().Subscribe(Console.WriteLine);

        // Send tasks.
        tasks.OnNext(fromResult);
        tasks.OnNext(run);
        tasks.OnNext(asyncAwait());

        Console.ReadLine();
    }
}

Fächer

Warum ich Subjekte benutzen oder nicht benutzen soll, ist eine Frage, die ich nicht ausreichend beantworten kann. In der Regel jedoch finde ich, dass die Verwendung eines Subjekts dazu neigt, der "einfache Ausweg" zu sein, wenn es scheint, dass ein Operator noch nicht existiert.

Wenn Sie die Belichtung eines Themas in Bezug auf seine Sichtbarkeit für den Rest der Anwendung irgendwie einschränken können, dann verwenden Sie unbedingt ein Thema und tun dies. Wenn Sie jedoch nach Message-Bus-Funktionalität suchen, sollten Sie das Design der Anwendung überdenken, da Message-Busse Anti-Patterns sind.


1
2018-05-28 16:50



Themen sind nicht schädlich. Das ist wahrscheinlich sogar ein bisschen zu dogmatisch für mich (und ich bin der erste, der den Gebrauch von Subjekten ausplündert). Ich würde sagen, dass Themen einen Code-Geruch anzeigen. Du könntest es wahrscheinlich ohne sie besser machen, aber wenn du das eingekapselte in deiner Klasse behältst, dann behältst du wenigstens den Geruch an einem Ort.

Hier würde ich sagen, dass Sie bereits "Nicht-Standard" -Ereignismuster verwenden, und es scheint, dass Sie das nicht ändern wollen oder können. In diesem Fall scheint es, dass die Verwendung von Subjekten als Brücke es nicht schlimmer machen wird, als es ist.

Wenn Sie bei Null anfangen würden, dann würde ich vorschlagen, dass Sie tief über Ihr Design nachdenken und Sie werden wahrscheinlich feststellen, dass Sie einfach kein Thema brauchen.

Schließlich stimme ich den anderen Kommentaren zu, dass Sie ein FromEvent und ToTask verwenden sollten, aber Sie schlagen vor, dass diese nicht funktionieren. Warum? Ich denke nicht, dass Sie fast genug von Ihrer Code-Basis zur Verfügung stellen, um bei Design-Fragen wie dieser zu helfen. z.B. Wie entsteht die nichtdeterministische Aufgabe? und durch was? Was ist das eigentliche Problem, das Sie versuchen zu lösen? Wenn Sie ein vollständiges Beispiel bereitstellen könnten, erhalten Sie möglicherweise die Aufmerksamkeit, die Sie suchen.


1
2018-06-04 07:58