Devo aprire un file di salvataggio del gioco, leggerlo, magari modificarlo e quindi salvarlo.
La struttura del salvataggio è abbastanza semplice: è un oggetto con alcuni membri, alcuni dei quali sono dati, mentre altri sono altri oggetti, quegli oggetti hanno alcuni membri, alcuni dei quali sono dati, mentre altri sono altri oggetti, vedi dove sta andando ...
Poiché il gioco è ancora in sviluppo e il formato di salvataggio è in continua evoluzione, gli sviluppatori del gioco hanno aggiunto un membro di versione come int a qualsiasi oggetto che viene modificato.
Ho un codice che ho scritto, ma è incorporato nel mio programma, e voglio estrarlo e creare una DLL che, quando viene fornito un flusso, prova a leggerlo, restituisce l'oggetto di salvataggio se tutto va bene, o restituire un errore se non ... ... in qualche modo.
Ora, il flusso è abbastanza semplice:
- Apri un oggetto
- Verifica se la versione corrisponde a
- Se lo fa, continua a leggere fino al completamento, membri o oggetti (nel qual caso goto 1)
- In caso contrario, prendi nota delle informazioni (attesa e leggi la versione, il nome della classe, le ho disponibili a quel punto) e interrompi ogni ulteriore lettura del file. È sufficiente restituire un errore.
Il modo in cui lo faccio attualmente è con i macro. La ragione di ciò è che devo controllare la versione più di 40 volte, e non voglio davvero duplicare la stessa logica che ruota intorno a questo, tanto più che un singolo risultato di controllo della versione dovrà essere valutato su ogni livello fino a quando raggiunge la radice dell'oggetto.
La macro ottiene la versione attesa e attuale e se tutto va bene, continuerà il programma, ma se qualcosa non funziona, registrerà il nome della classe e tornerà dalla funzione in cui si trovava, restituendo il versione corrente, mentre altrimenti la funzione continuerà e restituirà 0. Come questo:
#define CHECK_VERSION(currentValue, expectedValue) {int versionCheck = checkVersion(currentValue, expectedValue); if (versionCheck != 0) return versionCheck;}
//checkVersion() is a function that returns 0 if all is good or, if not, logs it to file and returns the currentValue)
int SomeObject::read(...) {
int objectVersion;
someReader::readInt(&objectVersion);
CHECK_VERSION(objectVersion, expectedVersion);
//read other stuff
return 0;
}
Ovviamente, ciò significa che ogni volta che un oggetto legge un altro oggetto, deve controllare se il valore restituito è 0 (se così va bene) o meno (in tal caso, restituire immediatamente quel valore) che è un'altra macro (e quale è ripetuto su ogni livello della struttura, per vedere se qualche oggetto interno non è stato letto)
Alla fine, questo rende un sistema contorto che funziona, ma non sono sicuro di come separarlo in una DLL, né pensare che sia la soluzione migliore.
Il problema principale qui è che voglio creare un modo per l'utente finale, quando prova a leggere un salvataggio o ottiene il salvataggio, o in caso di errore ottiene il nome dell'oggetto che ha fallito insieme al numero di versione che ha causato la mancata corrispondenza.
Non posso semplicemente scriverlo su file, ho bisogno di ottenere in qualche modo le informazioni al livello più alto e lasciare che l'utente decida su come gestire il problema e se registrare qualsiasi cosa o meno.
Quindi la domanda è, come posso strutturare questo? Quando controllo la versione di un oggetto e fallisce, cosa devo fare? Provare a catturare con la mia propria eccezione che si propagherebbe all'oggetto root sembrerebbe un'idea terribile, data la profondità dello stack.
Devo fare i classici codici di errore e creare un oggetto che contenga dati di errore e riportarlo semplicemente verso l'alto, analogamente a come ho restituito il numero singolo? Avrei ancora bisogno di usare macro per tornare presto alla funzione, che lo renderà di nuovo brutto, o mi costringerà a ripetere un sacco di codice che ancora non va bene. Ma questa è l'unica opzione a cui posso pensare in questo momento.
C'è un modo migliore per gestirlo che sarebbe più elegante e non richiederebbe l'uso di macro mantenendo la duplicazione del codice al minimo?
Se vuoi controllare il mio codice esatto, puoi vederlo qui . Il collegamento è al commit pertinente, se qualcuno si imbatte in questo in futuro. Le classi che vuoi guardare sono "EntityCreationData" e "VersionCheck". Il problema appare in molti altri, ma quelli dovrebbero dipingere l'immagine abbastanza bene.