2009-06-26 7 views
6

Recientemente me he encontrado necesitando (sí, necesitando) definir declaraciones absurdamente largas switch y declaraciones enum en código C#, pero me pregunto qué sienten las personas es la mejor manera de dividirlas en subsecciones lógicas. En mi situación, tanto los valores de enum como los casos (que se basan en los valores enum) tienen agrupaciones bastante claras, aunque no estoy seguro de cómo reflejar esto en el código.¿Usaría regiones dentro de declaraciones de cambio/enum largas?

Tenga en cuenta que en mi código, tengo aproximadamente 5 grupos de entre 10 y 30 valores enum/casos cada uno.

Las tres opciones vagamente sensibles puedo prever son:

  1. Definir #region bloques alrededor de todos los grupos lógicos de los casos los valores/enum dentro de la declaración (opcionalmente separados por líneas en blanco).
  2. Comenta cada grupo con su nombre, con una línea en blanco antes de cada comentario de nombre de grupo.
  3. No haga nada en absoluto: simplemente deje el interruptor/enumeración como una enorme lista de casos/valores.

¿Qué prefieres? ¿Tratarías las enumeraciones y los interruptores por separado? (Esto me parecería un poco extraño.) Ahora, no diría que hay una respuesta correcta/incorrecta a esta pregunta, aunque de todos modos estaría muy interesado en escuchar cuál es el consenso general de las opiniones.

Nota 1: Esta situación en la que podría tener potencialmente una declaración enum extremadamente larga de 50/100 + valores es, por desgracia inevitable (y de manera similar con el interruptor), ya que estoy intentando escribir un analizador léxico (tokenizador), y esto parecería ser el enfoque más razonable por varias razones.

Nota 2: Soy consciente de que ya existen varias preguntas duplicadas sobre la cuestión de si usar regiones en código general (para estructurar clases, principalmente), pero siento que mi pregunta aquí es mucho más específica y hasn todavía no se ha abordado.

+0

acaba de editar mi respuesta. Espero que ayude :) –

Respuesta

3

Claro, la región de esas cosas. Probablemente no cambien demasiado, y cuando lo hagan, puede expandir la región, hacer los cambios, colapsarla y pasar al resto del archivo.

Ellos están ahí por una razón, úselos para su ventaja.

+0

Esto ha sido más o menos mi pensamiento antes de hacer esta pregunta. Tiendo a considerar el uso excesivo de regiones algo "malvadas", pero esto parece ser una excepción. – Noldorin

1

Lo dejaría como una enorme lista de casos/valores.

+0

La razón es que no te gustan las regiones en general, lo tomo? (Este puede ser un buen punto.) – Noldorin

+0

+1 No me gustan las regiones conocidas como código ofuscación. – kenny

+0

No me gustan las regiones en general o en esta instancia específica :). Me gusta usar ctrl + m + o para contraer los archivos de clase. Las regiones rompen mi intención porque veo la región en lugar del código. –

0

Deshágase de las enumeraciones y conviértalas en objetos. Luego puede llamar a los métodos de sus objetos y mantener el código separado, mantenible y no una pesadilla.

Hay muy pocos casos en los que realmente necesitaría usar una enumeración en lugar de un objeto y a nadie le gusta las declaraciones de conmutación larga.

+0

Ver mi primera nota. Este es un lexer (como parte de un compilador) que estoy escribiendo. El único enfoque que he visto en el código existente es usar una enumeración, aunque estos ejemplos generalmente solo definían uno para una gramática muy simple, por lo que realmente no necesitaban ninguna agrupación. – Noldorin

+0

No creo que eso cambie mi respuesta. Sin ver la fuente, tengo que creer que se pueden dividir en objetos de valor. –

+0

Desafortunadamente, realmente necesito especificar los valores con una sola estructura de datos de algún tipo. Debería haber declarado que la enumeración representa un "tipo de token" en el lexer, y debe almacenarse dentro de una estructura Token. – Noldorin

1

Si hay algunos casos que tienen el mismo bloque de código, con el patrón de diseño de Estrategia, podría eliminar el bloque de interruptores. Esto puede crear muchas clases para ti, pero mostrará cuán complejo realmente es, y divide la lógica en clases más pequeñas.

+0

Sugerencia interesante. No estoy muy familiarizado con el patrón de estrategia. ¿Es realmente relevante aquí, en el caso de que mi enumeración represente un conjunto de tipos de tokens (y estoy escribiendo esto para un compilador)? – Noldorin

+0

No veo mucho problema al usar Strategy allí. Básicamente, creas clases responsables de hacer las lógicas dentro de cada bloque de casos. Es el que instancia la clase más grande (el que tiene el interruptor blcok) que define qué clase lógica usará. – mkato

3

También podría tener un Dictionary < [your_enum_type], Action> (o Func en lugar de Action) o algo así (teniendo en cuenta que sus funciones tienen una firma similar).Posteriormente, se podría en lugar de utilizar un interruptor, en lugar de:

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

usted podría tener algo como:

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

Este método ciertamente tiene sus ventajas en muchas circunstancias (especialmente en bloques de cajas largas). Sin embargo, en mi opinión, esto solo está retrasando los casos de declaración de cambio a un método que agrega elementos a un diccionario, y realmente no ayuda con la agrupación. – Noldorin

+0

En mi humilde opinión, no es exactamente lo mismo: esta es una buena manera de dividir esas líneas de adición de diccionarios en varios métodos. También le brinda un nivel adicional de abstracción a través de los delegados: puede agregar cualquier delegado a la lista desde cualquier lugar de su código. – Groo

+0

@samuel: Gracias por agregar el código de ejemplo. De hecho, la forma en que puede dividir la inicialización del diccionario en métodos es bastante ventajosa. Estoy empezando a gustarme esta solución ahora. :) – Noldorin

0

He aquí un buen acceso directo para las personas que utilizan regiones.

estaba el cambio entre Eclipse y Visual Studio cuando traté de ir a pantalla completa en VS pulsando

Ctrl-M-M

y he aquí, la región cerrada y expandida!

+0

Sí, hay algunos atajos útiles, que creo que hacen que las regiones sean menos molestas de lo que podrían ser. :) – Noldorin

Cuestiones relacionadas