2011-01-02 3 views
0

ich eine Methode, die auf dem ENUM basiert und am Anfang klar zu sein, haben wir diese Situation:Simplyfing Code mit vielen ifs

public void MyMetohd(Somestatus status) 
{ 
if(status == Somestatus.Enum1) 
{ 
DoA(); 
DoB(); 
DoC(); 
DoD(); 
DoE(); 
} 
if(status == Somestatus.Enum2) 
{ 
DoA(); 
DoB(); 
DoC(); 
DoD(); 
} 

if(status == Somestatus.Enum3) 
{ 
DoA(); 
DoB(); 
DoC(); 
} 

if(status == Somestatus.Enum4) 
{ 
DoA(); 
DoB(); 
} 

if(status == Somestatus.Enum5) 
{ 
DoA(); 
} 
} 

Wie würden Sie diese Art von Code zu optimieren (es isn‘ t meins)?

+0

Sprichst du von einer Plain Vanilla Enum, oder ist es eine Flagge? – Ragesh

+0

Was meinst du mit optimieren? Was genau sind deine Leistungsgrenzen und was begrenzt sie im Moment? –

+1

Ich frage mich, warum niemand Duffs Gerät erwähnt: http://en.wikipedia.org/wiki/Duff%27s_device – ruslik

Antwort

6

Überprüfen Sie, ob Sie Ihren Code nicht umstellen können, um eine Strategy Pattern zu verwenden. (Überprüfen Sie auch this). Sie können es mit einer Fabrikmethode oder Fabrikklasse kombinieren.

0

Auf den ersten Blick ein switch Aussage scheint der beste Ansatz zu sein, aber Sie haben eine Menge wiederholt Code sogar in das bekam:

switch (status) 
{ 
    case Somestatus.Enum1: 
     DoA(); 
     DoB(); 
     DoC(); 
     DoD(); 
     DoE(); 
     break; 
    case Somestatus.Enum2: 
     DoA(); 
     DoB(); 
     DoC(); 
     DoD(); 
     break; 
    ... 
} 

Während dies besser ist es immer noch nicht ideal ist, wie Sie haben Die Anrufe an DoA usw. wiederholt.

+1

Ausgenommen ohne zu brechen. (Warte, erlaubt C#, dass Case-Anweisungen ohne Unterbrechung durchfallen?) – BoltClock

+0

Wenn Sie die Pause weglassen; Wird es zu den anderen Werten des Status weitergehen? –

+0

@BoltClock - Nein, du kannst nicht in C# durchfallen, du musst 'goto' verwenden. – ChrisF

0

Wenn Sie an der gleichen Bedingung und anderen Wert dafür arbeiten, zu dieser Zeit besser verwenden Sie switch..case ... Verwenden Sie If..else, wenn Sie mehrere Bedingungen testen möchten.

0

könnte man auch „invertieren“ die Logik, wenn das es einfacher macht (abhängig von der Anzahl der Aufzählungen gegen die Anzahl der verschiedenen Aktionen zur Deckung):

if(status == Somestatus.Enum1 || status == Somestatus.Enum2) 
DoA(); 

if(status == Somestatus.Enum1 || status == Somestatus.Enum4) 
DoB(); 

... 
+0

Das ist noch mehr Code – BoltClock

3

Sie einen Wörterbuch Schlüssel auf die verwenden können, Enum-Wert und mit einer Liste von Action oder Action<T> ausgeführt werden.

Dictionary<int,IList<Action>> actionsPerEnumValue; 

Füllen Sie dieses Wörterbuch mit den Enum-Werten und den Aktionen für jedes.

In Ihrer Funktion erhalten Sie die Liste der Funktionen pro Wert und rufen Sie jede Aktion auf.

foreach(var act in actionsPerEnumValue[status]) 
{ 
    act(); 
} 

Siehe this SO für ein Beispiel beantworten.

5

verwenden, sollten Sie einen Vergleich verwenden können, wenn Sie die Werte der einzelnen Mitglieder des enum eingestellt.

Dann verwenden Sie einfach Vergleich, um Ihren Code zu tun. Weil Sie immer DoA() machen, fangen Sie damit an.

if(status <= Somestatus.Enum5) 
    DoA(); 

if(status <= Somestatus.Enum4) 
    DoB(); 

if(status <= Somestatus.Enum4) 
    DoC(); 
... 

Fahren Sie so weiter. Auf diese Weise werden alle Ihre Funktionen aufgerufen, wenn der Wert Enum1 ist.

+0

Gutes Beispiel, ich denke du meinst Auf diese Weise werden alle deine Funktionen aufgerufen, wenn der Wert Enum1 ist, da Enum1 das einzige Szenario ist, in dem alle 5 Methoden ausgeführt werden sollten –

+0

Ich denke, dass su ch 'Lösung' ist schwer zu lesen und wird sehr schwer zu warten sein. –

+0

++ So würde ich es machen. –

0

EDITED:

// ANOTHER WAY 
public void MyMetohd(Somestatus status) 
{ 
    switch(status) 
    { 
     case Somestatus.Enum1: 
      do_("ABCDE"); 
      break; 
     case Somestatus.Enum2: 
      do_("ABCD"); 
      // and so on... 
     } 
} 

public static void do_(string s) 
{ 
    foreach(char ch in s) 
    { 
     switch(ch) 
     { 
      case 'A': 
       doA(); 
       break; 
      case 'B': 
       doB(); 
       break; 
      case 'C': 
       doC(); 
       break; 
      case 'D': 
       doD(); 
       break; 
      case 'E': 
       doE(); 
       break    
     } 
    } 
} 
+2

Ihr erster Weg kompiliert nicht, wie zuvor erwähnt, erfordert C# eine explizite Sprunganweisung und fällt nicht durch. – Brook

+0

@Brook: Danke Mann! Ich werde das jetzt nie vergessen :) +1 –

+0

Kein Problem, ich dachte das gleiche zuerst, zusammen mit ein paar anderen Leuten. Die andere Sache ist, dass Sie begrenzt sind, welche Sprunganweisungen Sie verwenden können (break oder goto). Es wäre schön, wenn Sie "continue" verwenden würden, um explizit durchzufallen. – Brook

5

von optimize werde ich nehme an, Sie bedeuten "Dryer machen".

Du wird eine Balance zwischen Code hat zu schlagen, die leicht zu lesen ist (was, was Sie haben, ist, wenn auch etwas wiederholend) und Code, die so wenig wie möglich

einfach wiederholt eingeben das macht mich sich schmutzig anfühlen, aber wenn Sie wollen, ist TROCKEN und weniger LOC, ich denke, es würde tun, was Sie wollen.

switch (status) 
      { 
       case Somestatus.Enum1: 
        DoE(); 
        goto SomeStatus.Enum2; 
       case Somestatus.Enum2: 
        DoD(); 
        goto SomeStatus.Enum3; 
       case Somestatus.Enum3: 
        DoC(); 
        goto SomeStatus.Enum4; 
       case Somestatus.Enum4: 
        DoB(); 
        goto SomeStatus.Enum5; 
       case Somestatus.Enum5: 
        DoA(); 
        break; 
       default: 
        throw new InvalidArgumentException("Unknown Status"); 
      } 
0

Verwenden Sie ein Muster, um dies zu lösen, wird die beste Lösung sein, wie die anderen vorgeschlagen haben. Ich wollte noch eine andere Lösung anbieten.

Ich empfehle sehr, dies jedoch nicht zu tun.

public void MyMetohd(Somestatus status) 
    DoA(); 
    if (status != SomeStatus.Enum5) { 
     DoB(); 
     if (status != SomeStatus.Enum4) { 
      DoC(); 
      if (status != SomeStatus.Enum3) { 
       DoD(); 
       if (status != SomeStatus.Enum2) { 
        DoE(); 
       } 
      } 
     } 
    } 
} 
0

Obwohl ich mich für die Lösung von Brook selbst entscheiden würde, möchte ich auf eine andere elegante und kurze Lösung hinweisen.

public void MyMethod(Somestatus status) 
{ 
    foreach (Action toDo in new Action[] { DoA, DoB, DoC, DoD, DoE }.Take(5 - (int)status)) 
     toDo(); 
} 

Dies setzt jedoch voraus Somestatus ist wie folgt definiert:

enum Somestatus 
{ 
    Enum1, 
    Enum2, 
    Enum3, 
    Enum4, 
    Enum5 
} 

Ich mag diese Lösung als akademische und da ist sehr kurz, aber es ist sicherlich nicht groß Lesbarkeit oder Wartbarkeit haben.