Sto comunicando con un dispositivo collegato al computer tramite com port. Il dispositivo accetta determinati comandi predefiniti per interagire con esso. Sto essenzialmente creando un'API più astratta su quella fornita dal dispositivo.
Ho incapsulato le caratteristiche del Command
s che uso, in modo che possa semplicemente lanciare quegli oggetti nella mia classe Connection
, che gestisce la porta com.
connection.Send(new FooCommand());
connection
poi
- sposta
ICommand
in un oggettoSerialPort
utilizzato internamente - ascolta
SerialPort.DataReceived
per il risultato atteso - invia il prossimo
ICommand
(se ce n'è uno)
Fin qui tutto bene.
Per alcuni ICommand
, il dispositivo restituisce valori significativi (e non riconosce semplicemente la ricezione). Questi possono essere gestiti in callback opzionali Action<>
, che vengono passati al costruttore.
connection.Send(new BarCommand(response => Console.WriteLine(response)));
Funziona bene solo per ottenere un valore, ma diventa complicato per comunicazioni più complesse che inviano più istruzioni inviate che dipendono l'una dall'altra. Per illustrare, supponiamo che il valore restituito di un comando possa essere necessario per inviarne un altro.
La soluzione banale è mettere la seconda chiamata nella risposta callback del primo.
connection.Send(new BarCommand(response => connection.Send(new BazCommand(response)));
Questo diventa rapidamente disordinato. Una soluzione più leggibile potrebbe essere quella di memorizzare la risposta in una variabile.
var baz = new BazCommand();
connection.Send(new BarCommand(response => baz.Parameter = response));
connection.Send(baz)
Ora però BazCommand
deve essere mutabile , perché sarà completato (con il valore necessario per la sua proprietà parameter
) solo dopo è passato al metodo connection.Send()
. Significa anche che connection.Send()
deve valutare il suo parametro pigramente.
Anche in questo semplice esempio, l'ordine delle operazioni è già un po 'oscurato.
La situazione peggiora se l'invio di BazCommand
debba dipendere dalla risposta. Lambdas non è adatto per questo tipo di codice. È possibile utilizzare un metodo.
connection.Send(new BarCommand(responseHandler));
private void responseHandler(bool response) {
if(response) connection.Send(baz)
Questo porta a dozzine di metodi come responseHandler
che essenzialmente gestiscono le diverse transizioni di stato del mio oggetto (non una cosa negativa di per sé), che amplifica il codice e riduce la leggibilità .
Non ho molta esperienza con C # e ho bisogno di una guida su come migliorare il codice di comunicazione.
È un caso d'uso per async
/ await
?
Mi permetterebbe di scrivere codice come il seguente?
bool response = connection.Send(new BarCommand);
/* stop here until response is actually set to a value comming from the device */
connection.Send(new BazCommand(response))
o
bool response = connection.Send(new BarCommand);
/* stop here until response is actually set to a value comming from the device */
if (response) connection.Send(new BazCommand())