La decisione su quale tecnologia utilizzare sarà in gran parte relativa alle competenze del tuo team e al pubblico a cui è rivolto il tuo SDK, e in una certa misura se la tua API a lungo termine trarrà vantaggio dall'essere un fornitore di flussi osservabili.
Rx.NET è un modo molto potente e flessibile di fare le cose, e raccomanderei qualsiasi sviluppatore .NET che abbia bisogno di gestire simultaneità e / o flussi di eventi per esaminarlo.
(Suppongo che per "IObservable" intendi Rx.Net o stai guardando in streaming su Akka o qualcosa del genere?)
Tuttavia, entrare nel modo di pensare osservabile da parte di IO può essere una curva di apprendimento ripida.
C'è molta sovrapposizione tra Task e Rx.NET. Una spiegazione della sovrapposizione è qui ma secondo me è di parte a favore di Task.
Se prevedi che la tua API si occuperà di flussi asincroni, come il ritorno di lunghi elenchi di dati, o la guida di un modello push, o se desideri combinare più flussi, allora guarda in Rx.NET
Se si prevede che la propria API trarrà vantaggio da LINQ su flussi (con Rx.NET è possibile interrogare facilmente IObservables in quanto sono la versione "push" di IEnumerable, la versione "pull"), quindi esaminare Rx.NET. Per esempio, guarda. Dove. Seleziona. Seleziona Mamma. Esci. Scorri. Operatori di scansione in Rx.NET e decidi se ne avrai molti usi.
Se vedi che la tua API diventerà un servizio di streaming del modello push e se disponi delle competenze disponibili, potresti prendere seriamente in considerazione Rx.NET
Se è solo il piccolo problema che hai descritto nel tuo post originale, potrebbe non valere la pena di sovraccaricare l'apprendimento del modo Rx a meno che tu non abbia già competenze a portata di mano. In sostanza, la catena di compiti (vedere Attività secondarie associate qui ) è un IObservable Rx minimizzato. Il vantaggio è che questo codice è intuitivo per molti sviluppatori. Non è necessario visualizzarlo come IObservable vs Callback, un'attività non è un callback e le attività figlio (passaggi intermedi) possono essere restituite come una raccolta di attività (ad esempio: è possibile comporre le attività come un elenco come attività finale + task intermedio, quindi attendere When Any o alcuni di questi, magari allegare l'intermedio come task secondari).
Aggiornamento: la preoccupazione sollevata nell'aggiornamento secondo cui il messaggio di completamento dell'operazione verrà generato con un valore nullo durante le fasi intermedie non ha alcun senso. Indipendentemente dall'approccio adottato, i passaggi intermedi non descriveranno il motivo del completamento dell'operazione, a meno che, ovviamente, il passaggio intermedio sia post-hoc come fase finale.
Nel 1 ° scenario (Attività): la tua azione intermedia non solleverà un motivo di completamento (null).
Nel secondo scenario (Osservabili): le tue azioni intermedie non risolveranno un motivo di completamento.
Qual è la differenza?
Quello che dovresti fare nel caso dell'Osservable è dichiararlo osservabile come "risultato dell'azione". Questo è semanticamente equivalente a Task (un risultato futuro ). Dichiara X tipi di messaggio di risultato. Ad esempio:
public class ResultMessage
public class FinalResultMessage: ResultMessage
etc
Quindi puoi implementare Task o IObservable come desideri.
Se segui la rotta di Osservabile. Puoi offrire .Finally
nel sottoscrittore o nell'osservabile per gestire FinalResultMessage.
In breve, non rendere l'API un IObservable ma IObservable se segui questa strada e applica lo stesso pensiero anche per Task.