2016-04-22 9 views
2

Ich habe einfache Klasse, die Loops erstellen können:Pause Schleife innerhalb eines Delegierten

public class SimpleLoop 
{ 
    public int I { get; set; } 
    public Predicate<int> Condition { get; set; } 
    public int Increment { get; set; } 
    public Action<int> Action { get; set; } 

    public SimpleLoop(int i, Predicate<int> condition, int increment, Action<int> action) 
    { 
     I = i; 
     Condition = condition; 
     Increment = increment; 
     Action = action; 
     Invoke(); 
    } 

    private void Invoke() 
    { 
     for (int i = I; Condition.Invoke(i); i += Increment) 
     { 
      Action.Invoke(i); 
     } 
    } 
} 

Dann kann ich auf diese Weise diese Schleife nennen:

new SimpleLoop(0, i => i <= 12, 1, delegate (int i) 
{ 
    Console.WriteLine(i); 
}); 

Alles funktioniert gut, aber ich don ‚t wissen, wie aus der Schleife zu brechen, weil ich nicht die Schlüsselwörter break und continue in einem void verwenden kann. Ich fand heraus, dass ich return kann gleiche Wirkung wie continue zu bekommen, aber ich kann die Schleife nicht ausbrechen.

Ich habe auch andere „Loop-Klassen“ auf der Basis dieser Klasse. Sie sehen ziemlich ähnlich aus, aber dort benutze ich einen benutzerdefinierten Delegierten anstelle von Action

+0

Ich gehe davon aus, dass dies nur mit Code spielen ...weil es im Produktionscode fast unbrauchbar ist: \ –

+0

Sie können einfach die aufgerufene Funktion einen boolean zurückgeben, der angibt, ob fortzufahren oder nicht ... – Nyerguds

Antwort

1

Warum nicht einfach eine Func<int, bool> statt Action<int> verwenden und erfordern, dass die Delegierten Rückkehr true fortzusetzen oder false zu brechen?

Zum Beispiel:

public class SimpleLoop 
{ 
    public int I { get; set; } 
    public Predicate<int> Condition { get; set; } 
    public int Increment { get; set; } 
    public Func<int, bool> Action { get; set; } 

    public SimpleLoop(int i, Predicate<int> condition, int increment, Func<int, bool> action) 
    { 
     I = i; 
     Condition = condition; 
     Increment = increment; 
     Action = action; 
     Invoke(); 
    } 

    private void Invoke() 
    { 
     for (int i = I; Condition.Invoke(i); i += Increment) 
     { 
      if (!Action.Invoke(i)) 
       break; 
     } 
    } 
} 

Und dann:

new SimpleLoop(0, i => i <= 12, 1, delegate (int i) 
{ 
    Console.WriteLine(i); 
    return i < 5; 
}); 
+0

Vielen Dank für Ihre Antwort. Ich denke, es ist die beste Lösung, aber ich würde eine 'enum' anstelle von' bool' verwenden, so dass ich zwischen 'break',' continue' und nichts wählen kann. – daniel59

+0

@ Fuzzi59 Ja, diese Enum ist eine gute Idee. –

0

Verwenden Sie die gleiche Weise wie Paralell Linq es tut. Ihr Delegat sollte nicht nur den Wert annehmen, sondern auch ein Objekt, das den Status der Iteration selbst darstellt.

Action<int> action 

wird

Action<SimpleLoopState, int> ... 


delegate (state, value) => 
{ 
state.Break(); 
} 
0

Ich bin nicht sicher, wo Sie die Schleife zu brechen versuchen; Ich habe versucht, es bei Wert 9 zu brechen, und es hat funktioniert. Hier ist der Code

enter code here 
    private void Invoke() 
    { 
     for (int i = I; Condition.Invoke(i); i += Increment) 
     { 
      Action.Invoke(i); 
      if(i.Equals(9)) 
      break; 
     } 
    } 

Dank Manish Prasad

+0

i.Equals (9) ist das gleiche wie i == 9 – riki

0

ich einen Weg gefunden, aus der Schleife zu brechen. Ich habe eine Klasse basierend auf der Klasse Exception und nannte es BreakException:

public class BreakException : Exception { } 

Dann habe ich eine statische Methode hinzugefügt zu werfen ein BreakException:

public static void Break() 
{ throw new BreakException(); } 

Jetzt kann ich diese Ausnahme fangen, um aus der Schleife:

private void Invoke() 
{ 
    for (int i = I; Condition.Invoke(i); i += Increment) 
    { 
     try 
     { 
      Action.Invoke(i); 
     } 
     catch (BreakException) 
     { break; } 
    } 
} 

HINWEIS: Wenn ich rufe die Break -m ethode in einem try-catch Block muss ich sicherstellen, dass ich nicht fangen ein BreakException und wenn ich einen fangen muss ich rufen die Break -Methode wieder:

new SimpleLoop(0, i => i <= 12, 1, delegate (int i) 
{ 
    try 
    { 
     if (i == 5) 
     { throw new ArgumentException(); }//raise an other Exception 
     if (i > 10) 
     { SimpleLoop.Break(); } 
      Console.WriteLine(i); 
    } 
    catch (Exception exception)//Catching every Exception, it would be better to catch just ArgumentExceptions 
    { 
     if (exception.GetType() == typeof(BreakException)) 
     { SimpleLoop.Break(); }//Call Break again 
     Console.WriteLine("Error at " + i); 
    } 
}); 
+0

Eine Ausnahme kostet Sie eine Menge Leistung (relativ zu der Arbeit, die Sie tun). In vielen Projekten ist eine Leistung, die für etwas, das wahrscheinlich weit verbreitet ist, so groß ist, nicht akzeptabel ... – riki