Come progettare l'accesso a diversi oggetti di testo nella risposta del protocollo

3

Ho scritto una libreria di comunicazione per un protocollo di dispositivo industriale. Il frame di risposta contiene un array di byte come dati di payload. I dati del payload sono costituiti da diversi "oggetti" di tipi diversi, come interi, float e altri dati più complessi come date o codifiche di stringhe diverse.Per rendere questo più divertente, i dati potrebbero anche essere in ordine di byte diverso.

La mia soluzione attuale è di avere un oggetto dati generico, che contiene le informazioni generali come posizione nell'array di byte e nell'ordine dei byte, e vari oggetti ereditati per gestire i diversi tipi di dati:

public abstract class DataObject{
    private readonly int _position;
    public int Position {
        get { return _position; }
    }
    private readonly ByteOrder _byteOrder;
    public abstract object Data { get;}

    /* snip */
}

public class FloatObject : DataObject {
    public abstract object Data {
        get{
            float floatValue;
            /* handle byte to float conversion */
            return floatValue;
        }
    }
}

public class StringObject : DataObject {
    public abstract object Data {
        get{
            string stringValue;
            /* handle byte to string conversion */
            return stringValue;
        }
    }
}

Ciò che non mi piace di questo è la gestione della proprietà dei dati. La classe base lo dichiara come un oggetto, quindi ogni volta che ho bisogno di trasmettere il risultato al tipo corrispondente. Se non dichiaro una proprietà Data nella classe base, ma in tutte le classi derivate, ho bisogno di eseguire il cast dell'oggetto dati sull'oggetto dati specifico, che è solo uno spostamento del problema. C'è qualche disegno migliore che potrei usare per risolvere questo problema?

    
posta Turbofant 24.09.2015 - 08:46
fonte

3 risposte

1

Se dichiari un tipo che in realtà dovrebbe contenere uno stato utile come object , non c'è davvero alcun modo di evitare le tipizzazioni dappertutto. Non c'è modo di aggirarlo.

Tuttavia, sembra che quello che stai facendo, ad un livello più alto, stia tentando di estrarre informazioni da un flusso di byte applicando regole formali per riconoscere modelli ben definiti nell'input e produrre da loro oggetti di dati che rappresentano il loro significato semantico.

Questo è un problema ben studiato in informatica: analisi . Il termine è generalmente utilizzato nel contesto del testo, codice sorgente per un linguaggio di programmazione, ma non c'è ragione per cui non si possano applicare le stesse tecniche a un flusso binario. Se dovessi lavorare con un sistema complicato come quello che stai descrivendo, una delle prime cose che farei è scrivere un parser per questo.

Il modo esatto per fare ciò dipende in gran parte da come viene definito il flusso di dati, ma probabilmente puoi utilizzare strumenti esistenti come il Protocollo Buffer , o un generatore di parser come ANTLR per occuparsi di molti lavori pesanti.

    
risposta data 24.09.2015 - 17:36
fonte
0

Dubito che si possa fare qualcosa attorno al tuo attuale design per evitare il casting.

Durante lo sviluppo ex novo, consiglierei di evitare la creazione di campi troppo tipizzati in modo astratto nelle classi, responsabili della gestione del protocollo. Ricorda LSP !

Invece di inventare il tuo formato di protocollo e serializzatori / deserializzatore, sarebbe interessante guardare Buffer del protocollo Google o gRPC .

    
risposta data 24.09.2015 - 17:34
fonte
0

Hai esaminato questa possibilità?

public abstract class DataObject<T>
    public byte[] RawData { get;}
    public abstract object DataAsObject { get;}
    public abstract T Data { get;}
public class FloatObject : DataObject<float>
    public float Data { get { ... } }
public class StringObject : DataObject<string>
    public string Data { get { ... } }

C'è qualche ragione per cui non funzionerebbe, che non riesco a vedere in questo momento?

    
risposta data 24.09.2015 - 17:41
fonte

Leggi altre domande sui tag