2012-06-23 23 views
8

Diciamo che abbiamo queste caselle di controllo:Come rendere questo codice più ASCIUTTO?

  • FooCheckBox
  • BarCheckBox
  • BazCheckBox

E questi metodi:

  • Foo
  • Bar
  • Baz

Voglio chiamare ogni metodo solo se la casella di controllo corrispondente è selezionata. Il codice potrebbe essere simile a questo:

void DoWork() 
{ 
    if (FooCheckBox.Checked) 
    { 
     Foo(); 
     Console.WriteLine("Foo was called"); 
    } 

    if (BarCheckBox.Checked) 
    { 
     Bar(); 
     Console.WriteLine("Bar was called"); 
    } 

    if (BazCheckBox.Checked) 
    { 
     Baz(); 
     Console.WriteLine("Baz was called"); 
    } 
} 

Consideriamo ora che invece di 3 caselle di controllo e 3 metodi che hanno molto di più. Come riscriverebbe il codice sopra per renderlo più DRY?

+0

[Codereview.SE] (http://codereview.stackexchange.com/) è più adatto per le domande di miglioramento del codice come questo. – outis

risposta

7

Direi per il caso che hai presentato, lasciare così com'è; non si vuole sovra-astratto senza una buona ragione, in quanto può rendere meno gestibile un codice base. Ovviamente il contesto è importante, ed è in definitiva un giudizio.

Detto questo, ecco come mi avvicinerei a questo. Crea una raccolta in cui ogni elemento contiene sia il controllo che il delegato dell'azione. Quindi esegui il ciclo e esegui la logica su ciascun elemento.

var items = new KeyValuePair<CheckBox, Action>[] { 
    new KeyValuePair<CheckBox,Action>(FooCheckBox, Foo), 
    new KeyValuePair<CheckBox,Action>(BarCheckBox, Bar), 
    new KeyValuePair<CheckBox,Action>(BazCheckBox, Baz) 
}; 

foreach (var item in items) 
{ 
    if (item.Key.Checked) 
    { 
     item.Value.Invoke(); 
     Console.WriteLine("Invoked " + item.Value.Method.Name); 
    } 
} 

Or (forse?) Meglio utilizzando Linq:

items.Where(item => item.Key.Checked).ToList().ForEach(item => new { 
    item.Value.Invoke(); 
    Console.WriteLine("Invoked " + item.Value.Method.Name); 
}); 
6

È possibile utilizzare un dizionario per tenere il passo con quali azioni si riferiscono a quali caselle di controllo. Quindi è possibile effettuare le seguenti operazioni:

foreach(KeyValuePair<CheckBox, Action> kvp in Dict) 
{ 
    if(kvp.Key.Checked) 
     kvp.Value.Invoke(); 
} 
+0

'Azione' non implica argomenti e nulla come tipo di ritorno. – Odys

+2

@odyodyodys Così fanno i 3 metodi proposti dall'OP. –

+0

corretto. Le sue chiamate al metodo non implicavano argomenti o tipi di ritorno. Anche se è possibile sostituire facilmente una Funzione al posto dell'azione se necessario. – MrWuf

2

Potrebbe essere fatto nel modo seguente:

void DoWork() 
{ 
    Func<Action, string, Tuple<Action, string>> toT = 
     (a, s) => new Tuple<Action, string>(a, s); 

    var map = new Dictionary<CheckBox, Tuple<Action, string>> 
    { 
     {FooCheckBox, toT(Foo, "Foo")}, 
     {BarCheckBox, toT(Bar, "Bar")}, 
     {BazCheckBox, toT(Baz, "Baz")}, 
    }; 

    foreach (var x in map.Keys) 
     if (x.Checked) 
     { 
      map[x].Item1(); 
      Console.WriteLine(map[x].Item2 + " was called"); 
     } 
} 

Ma penso che a volte non essendo molto secca è solo ok.

0

vorrei creare un Dictionary con <CheckBox, Func> e ciclo attraverso ogni valore:

Dictionary<CheckBox, Func> checkboxes = new Dictionary<CheckBox, Func>(); 
void Init() 
{ 
    checkboxes.Add(FooCheckBox, Foo); 
    checkboxes.Add(BarCheckBox, Bar); 
    checkboxes.Add(BazCheckBox, Baz); 
} 

void DoWork() 
{ 
    foreach (KeyValuePair<CheckBox, Func> checkbox in checkboxes) 
    { 
     if (checkbox.Key.Checked) 
     { 
      checkbox.Value(); 
      Console.WriteLine("{0} was called", checkbox.Text); 
     } 
    } 
} 
4

per semplicità vorrei andare con

void DoWork() 
{ 
    DoIfChecked(FooCheckBox, Foo, "Foo as Called"); 
    DoIfChecked(BarCheckBox, Bar, "Bar as Called"); 
    DoIfChecked(BazCheckBox, Baz, "Baz as Called"); 
} 
void DoIfChecked(CheckBox checkBox, Action action, string message) 
{ 
    if (checkBox.IsChecked) 
    { 
     action(); 
     Console.WriteLine(message); 
    } 
} 

ma si poteva fare qualcosa con la parte del messaggio se è che semplice, e potrei inserire alcuni errori di verifica a seconda del contesto locale.

Problemi correlati