2009-06-26 14 views
6

Recentemente mi sono trovato a dover (sì, a bisogno) definire dichiarazioni assurdamente lunghe switch e dichiarazioni enum in codice C#, ma mi chiedo cosa ritengano le persone il modo migliore per dividerle in sottosezioni logiche. Nella mia situazione, sia i valori di enum che i casi (che sono basati sui valori di enum) hanno raggruppamenti abbastanza chiari, tuttavia sono un po 'incerto su come rispecchiare questo codice.Utilizzeresti le regioni all'interno di dichiarazioni di switch/enum lunghi?

Si noti che nel mio codice, ho circa 5 gruppi di valori compresi tra 10 e 30 valori/casi ciascuno.

Le tre opzioni vagamente ragionevoli posso prevedere sono:

  1. Definire #region blocchi intorno tutti i gruppi logici di valori casi/enum all'interno della dichiarazione (opzionalmente separati da righe vuote).
  2. Commenta ogni gruppo con il suo nome, con una riga vuota prima di ogni commento del nome di gruppo.
  3. Non fare nulla - semplicemente lascia l'interruttore/enum come un elenco enorme di casi/valori.

Quale preferisci? Tratteresti separatamente enumerazioni e interruttori? (Questo sembrerebbe un po 'strano per me.) Ora, non direi che c'è una risposta giusta/sbagliata a questa domanda, anche se sarei comunque molto interessato a sentire quale sia il consensus generale delle opinioni.

Nota 1: Questa situazione dove potrei potenzialmente avere una dichiarazione estremamente lunga enum di 50/100 + valori è purtroppo inevitabile (e allo stesso modo con l'interruttore), dal momento che sto cercando di scrivere un lexer (tokeniser), e questo sembrerebbe quindi l'approccio più ragionevole per diversi motivi.

Nota 2: Sono pienamente consapevole del fatto che esistono già diverse domande duplicate sulla questione se utilizzare le regioni nel codice generale (per le classi di strutturazione, soprattutto), ma sento che la mia domanda qui è molto più specifico e hasn ancora stato affrontato

+0

ho appena modificato la mia risposta. Spero che aiuti :) –

risposta

3

Certo, prendi nota di queste cose. Probabilmente non cambiano molto, e quando lo fanno, puoi espandere la regione, apportare le modifiche, comprimerla e passare al resto del file.

Sono lì per un motivo, usarli a proprio vantaggio.

+0

Questo è stato più o meno il mio modo di pensare prima di fare questa domanda. Tendo a considerare un uso eccessivo delle regioni un po '"malvagio", ma questa sembra essere un'eccezione. – Noldorin

1

Vorrei lasciarlo come un elenco enorme di casi/valori.

+0

La ragione è che non ti piacciono le regioni in generale, lo prendo? (Questo potrebbe essere un punto giusto.) – Noldorin

+0

+1 Non mi piacciono le regioni aka il codice offuscamento. – kenny

+0

Non mi piacciono le regioni in generale o in questa specifica istanza :). Mi piace usare ctrl + m + o per comprimere i file di classe. Le regioni rompono la mia intenzione perché vedo la regione invece del codice. –

0

Sbarazzarsi delle enumerazioni e trasformarle in oggetti. Potresti quindi chiamare metodi sui tuoi oggetti e mantenere il codice separato, manutenibile e non un incubo.

Ci sono pochissimi casi in cui è effettivamente necessario utilizzare un enum anziché un oggetto e a nessuno piacciono le dichiarazioni di switch lunghe.

+0

Vedi la mia prima nota. Questo è un lexer (come parte di un compilatore) che sto scrivendo. L'unico approccio che ho visto nel codice esistente è l'uso di un enum - sebbene in genere questi esempi ne definissero solo uno per una grammatica molto semplice, quindi non c'era davvero bisogno di alcun raggruppamento. – Noldorin

+0

Non penso che cambi la mia risposta. Senza vedere la fonte, devo credere che possano essere scomposti in oggetti di valore. –

+0

Purtroppo, ho davvero bisogno di specificare i valori con una singola struttura dati di qualche tipo. Avrei dovuto affermare che l'enum rappresenta un "tipo di token" nel lexer e deve essere memorizzato all'interno di una struttura Token. – Noldorin

1

Se alcuni casi hanno lo stesso blocco di codice, utilizzando lo schema di progettazione della strategia, è possibile rimuovere il blocco switch. Questo può creare molte classi, ma mostrerà quanto sia davvero complesso e dividere la logica in classi più piccole.

+0

Suggerimento interessante. Non ho molta familiarità con il modello di strategia. È davvero rilevante qui, nel caso in cui il mio enum rappresenti un insieme di tipi di token (e sto scrivendo questo per un compilatore)? – Noldorin

+0

Non vedo molti problemi nell'usare la strategia lì. Fondamentalmente, si creano classi responsabili per eseguire le logiche all'interno di ciascun blocco di casi. È colui che istanzia la classe più grande (colui che ha l'interruttore blcok) che definisce quale classe logica userà. – mkato

3

Si potrebbe anche avere un dizionario < [your_enum_type], azione> (o Func invece di azione) o qualcosa del genere (considerando che le proprie funzioni hanno una firma simile).Poi si potrebbe invece di utilizzare un interruttore, invece di:

 switch (item) 
     { 
      case Enum1: func1(par1, par2) 
       break; 
      case Enum2: func2(par1, par2) 
       break; 
     } 

si potrebbe avere qualcosa di simile:

public class MyClass 
{ 
    Dictionary<int, Action<int, int>> myDictionary; 
    //These could have only static methods also 
    Group1Object myObject1; 
    Group2Object myObject2; 

    public MyClass() 
    { 
     //Again, you wouldn't have to initialize if the functions in them were static 
     myObject1 = new Group1Object(); 
     myObject2 = new Group2Object(); 
     BuildMyDictionary(); 
    } 

    private Dictionary<int, Action<int, int>> BuildMyDictionary() 
    { 
     InsertGroup1Functions(); 
     InsertGroup2Functions(); 
     //... 
    } 

    private void InsertGroup2Functions() 
    { 
     myDictionary.Add(1, group2.AnAction2); 
     myDictionary.Add(2, group2.AnotherAction2); 
    } 

    private void InsertGroup1Functions() 
    { 
     myDictionary.Add(3, group1.AnAction1); 
     myDictionary.Add(4, group1.AnotherAction1); 
    } 


    public void DoStuff() 
    { 
     int t = 3; //Get it from wherever 
     //instead of switch 
     myDictionary[t](arg1, arg2); 
    } 
} 
+0

Questo metodo ha certamente i suoi vantaggi in molte circostanze (in particolare blocchi lunghi). Tuttavia, per me questo è davvero solo differire i casi di switch statement a un metodo che aggiunge elementi a un dizionario e non aiuta molto con il raggruppamento. – Noldorin

+0

IMHO non è esattamente lo stesso - questo è un buon modo per dividere quei dizionari aggiungendo linee in più metodi. Inoltre ti offre un ulteriore livello di astrazione attraverso i delegati: puoi aggiungere qualsiasi delegato alla lista, da qualsiasi punto del tuo codice. – Groo

+0

@samuel: Grazie per aver aggiunto il codice di esempio. In effetti, il modo in cui è possibile suddividere l'inizializzazione del dizionario in metodi è piuttosto vantaggioso. Sto iniziando ad apprezzare questa soluzione ora. :) – Noldorin

0

Ecco una buona scorciatoia per le persone che utilizzano le regioni.

mi è stato il passaggio tra Eclipse e Visual Studio quando ho provato per lo schermo intero in VS premendo

Ctrl-M-M

ed ecco, la regione chiusa e ampliato!

+0

Sì, ci sono alcune scorciatoie a portata di mano, che penso che rendano le regioni meno fastidiose di quanto potrebbero potenzialmente essere. :) – Noldorin

Problemi correlati