Quali sono gli svantaggi nel mappare gli identificatori integrali alle enumerazioni?

16

Ho pensato di creare tipi personalizzati per identificatori come questo:

public enum CustomerId : int { /* intentionally empty */ }
public enum OrderId : int { }
public enum ProductId : int { }

La mia motivazione principale è di prevenire il tipo di bug in cui si passa accidentalmente un orderItemId a una funzione che si aspettava un orderItemDetailId.

Sembra che le enumerazioni funzionino perfettamente con tutto ciò che vorrei usare in una tipica applicazione Web .NET:

  • Il routing MVC funziona bene
  • La serializzazione JSON funziona bene
  • Ogni ORM che riesco a pensare funziona bene

Quindi ora mi chiedo, "perché non dovrei farlo?" Questi sono gli unici inconvenienti a cui posso pensare:

  • Potrebbe confondere altri sviluppatori
  • Introduce incoerenze nel tuo sistema se hai identificatori non integrali.
  • Potrebbe richiedere casting aggiuntivo, come (CustomerId)42 . Ma non penso che questo sarà un problema, dal momento che il routing ORM e MVC tipicamente passerà direttamente i valori del tipo enum.

Quindi la mia domanda è: cosa mi manca? Questa è probabilmente una cattiva idea, ma perché?

    
posta default.kramer 02.02.2016 - 19:46
fonte

4 risposte

7

È una buona idea creare tipo per ogni tipo di identificatore, principalmente per i motivi che hai indicato. Non lo farei implementando il tipo enum perché renderlo una struct o una classe appropriata ti offre più opzioni:

  • È possibile aggiungere la conversione implicita a int. Quando ci pensi, è l'altra direzione, int - > CustomerId, questa è la problematica che merita una conferma esplicita da parte del consumatore.
  • È possibile aggiungere regole aziendali che specificano quali identificatori sono accettabili e quali no. Non si tratta solo di un controllo debole se l'int è positivo: a volte, l'elenco di tutti gli ID possibili viene conservato nel database, ma cambia solo durante l'implementazione. Quindi è possibile verificare facilmente che l'ID specificato esista sul risultato memorizzato nella cache della query corretta. In questo modo, puoi garantire che la tua applicazione fallisca rapidamente in presenza di dati non validi.
  • I metodi sull'identificatore possono aiutarti a eseguire costosi controlli DB-esistenza o ottenere l'oggetto entità / dominio corrispondente.

Puoi leggere come implementarlo nell'articolo Functional C #: ossessione primitiva .

    
risposta data 05.02.2016 - 13:13
fonte
3

È un trucco intelligente, ma è comunque un trucco in cui si abusa di una funzionalità per qualcosa che non è lo scopo previsto. Gli hacker hanno un costo in termini di manutenibilità, quindi non è sufficiente che non si riescano a trovare altri inconvenienti, ma occorre anche avere vantaggi significativi rispetto al modo più idiomatico per risolvere lo stesso problema.

Il modo idiomatico sarebbe quello di creare un tipo di wrapper o una struttura con un singolo campo. Questo ti darà lo stesso tipo di sicurezza in un modo più esplicito e idiomatico. Sebbene la tua proposta sia dichiaratamente intelligente, non vedo alcun vantaggio significativo nell'utilizzo dei tipi di wrapper.

    
risposta data 05.02.2016 - 13:38
fonte
2

Dal mio POV, l'idea è buona. L'intenzione di dare tipi diversi a classi di identificatori non correlate, e altrimenti esprimere la semantica tramite tipi e lasciare che sia il compilatore a controllarla, è buona.

Non so come funzioni in .NET performance-wise, ad es. sono i valori enumerati necessariamente in scatola. Il codice OTOH che funziona con un database è probabilmente associato all'I / O e gli identificatori non saranno un collo di bottiglia.

In un mondo perfetto, gli identificatori sarebbero immutabili e paragonabili solo per l'uguaglianza; i byte effettivi sarebbero un dettaglio di implementazione. Identificatori non correlati avrebbero tipi incompatibili, quindi non potresti usarne uno per errore. La tua soluzione si adatta praticamente al conto.

    
risposta data 02.02.2016 - 22:41
fonte
-1

Non puoi farlo, le enumerazioni devono essere predefinite. Quindi, a meno che tu non sia disposto a pre-definire l'intero spettro dei possibili valori degli ID cliente, il tuo tipo sarà inutile.

Se lanci, sfiderai il tuo obiettivo principale di impedire di assegnare accidentalmente un ID di tipo A a un ID di tipo B. Quindi le enumerazioni non sono utili per il tuo scopo.

Questo solleva la domanda anche se sarebbe utile creare i tuoi tipi per ID cliente, ID ordine e ID prodotto discendendo da Int32 (o Guid). Posso pensare a dei motivi per cui ciò sarebbe sbagliato.

Lo scopo di un ID è l'identificazione. I tipi integrali sono già perfetti per questo, non si identificano più scendendo da essi. Non è richiesta alcuna specializzazione o desiderata, il tuo mondo non sarà rappresentato meglio avendo tipi diversi di identificatori. Quindi da una prospettiva OO sarebbe male.

Con il tuo suggerimento vuoi più della sicurezza del tipo, vuoi la sicurezza del valore e questo va oltre il dominio della modellazione, è un problema operativo.

    
risposta data 02.02.2016 - 21:45
fonte

Leggi altre domande sui tag