Creazione istanza di sottoclasse basata sull'input input di lettura

2

Per poter leggere i file da un altro progetto, sto copiando il codice di scrittura e adattandolo alle mie esigenze.

Sono giunto a un costrutto curioso che sembra davvero brutto, ma non so se c'è un altro modo per affrontarlo.

Il codice ha un aspetto simile al seguente:

int type = reader.readInt32():
BaseClass p = BaseClass.Instantiate((BaseClassEnum)type);
object.Read(reader);

Questo codice sembra carino, e lo è, ma il metodo BaseClass.Instantiate (tipo BaseClassEnum) lascia qualcosa a desiderare.

Fondamentalmente, si tratta di un'affermazione di caso switch gigante che crea un'istanza di una sottoclasse della classe di base in base al parametro di tipo passato.

C'è un modo per evitare l'interruttore qui? Posso creare un dizionario in cui mappare BaseClassEnum a qualche tipo di riferimento di classe che mi consenta di chiamarlo come costruttore? Qualcosa come:

Dictionary<int, ???> bindings = new Dictionary<int, ???>(){
    {BaseClassEnum1, SubClass1},
    {BaseClassEnum2, SubClass2}
}

//...

//Assuming SubClass1 has a constructor SubClass1()
BaseClass p = new bindings[BaseClassEnum1]();

//I could even create a new constructor SubClass(BinaryReader reader) and do
BaseCoass p = new bindings[BaseClassEnum1](reader);

Alla fine, il codice sarebbe simile a questo:

BaseClass p = new bindings[(BaseClassEnum)reader.ReadInt32()](reader);
    
posta Karlovsky120 22.12.2018 - 12:51
fonte

2 risposte

2

Una factory di classe / tipo (che è ciò che stai creando), è implementata in uno dei quattro modi di base.

  1. Istruzione switch o equivalente o una serie di istruzioni if / then / else
  2. Dizionario o altra struttura che consente di associare un valore a un tipo particolare
  3. Qualche variazione di chiamata per nome (che in C # significa riflessione)
  4. Abbonamento all'evento (non usato molto spesso) che probabilmente utilizzerà internamente uno degli altri metodi.

Le istruzioni switch sono brutte e, naturalmente, un po 'incline agli errori, i dizionari sono ugualmente brutti e hanno i loro errori, ma sono più facili da testare. La riflessione è generalmente più lenta e l'iscrizione all'evento è ancora più lenta.

Quindi, non c'è un proiettile d'argento.

Ciò che descriveresti sarà:

var binding = new Dictionary<int, Func<BaseClass>>(){{BaseClassEnum1, ()=> new SubClass1()},
                                                   {BaseClassEnum2, ()=>new SubClass2()}};


var p = new bindings[BaseClassEnum1]();

Esempio di lavoro al link (con alcune differenze nei nomi delle variabili).

Devo notare che sia l'esempio sopra sia l'esempio sono un po 'semplificati, in particolare se questo dovrebbe coprire tutte le sottoclassi possibili nella tua applicazione, il dizionario dovrebbe essere la sua proprietà / funzione in modo che tu possa testare ( tramite riflessione) che tutte le sottoclassi della tua applicazione sono presenti nella lista.

    
risposta data 22.12.2018 - 21:46
fonte
1

Se cambi i punti interrogativi ??? a Type puoi utilizzare var p = Activator.Createinstance(binding[BaseClassEnum1], reader)

risposta data 22.12.2018 - 14:52

fonte

Leggi altre domande sui tag