web-dev-qa-db-fra.com

Comment puis-je quitter une boucle List <string> .ForEach lors de l'utilisation d'un délégué anonyme?

Dans une boucle normale, vous pouvez sortir d'une boucle en utilisant break. Peut-on faire la même chose en utilisant un délégué anonyme?

Exemple InputString et result sont tous deux déclarés en dehors du délégué.

blackList.ForEach(new Action<string>(
    delegate(string item)
    {
        if(inputString.Contains(item)==true)
        {
            result = true;
            // I want to break here
        }
    }
));

Edit: Merci pour les réponses, je suis en train de lire votre livre à la minute John :) Juste pour mémoire, je reviens sur ce problème et retournai à une boucle normale de foreach mais j’ai posté cette question pour voir si j’ai manqué quelque chose .

34
SecretDeveloper

Comme d'autres l'ont écrit, vous ne pouvez pas quitter la boucle dans ForEach.

Pouvez-vous utiliser LINQ? Si tel est le cas, vous pouvez facilement combiner TakeWhile et une méthode d’extension ForEach personnalisée (qui semble avoir pratiquement tous les projets de nos jours).

Dans votre exemple, cependant, List<T>.FindIndex serait la meilleure alternative - mais si vous ne le faites pas réellement, veuillez publier un exemple de ce que vous vraiment voulez faire.

37
Jon Skeet

Il n'y a pas de boucle à laquelle on a accès, à partir de laquelle rompre. Et chaque appel au délégué (anonyme) est un nouvel appel de fonction, de sorte que les variables locales n’aideront pas. Mais puisque C # vous donne une fermeture, vous pouvez définir un drapeau et ne rien faire ensuite dans les appels suivants:

bool stop = false;
myList.ForEach((a) => {
  if (stop) {
    return;
  } else if (a.SomeCondition()) {
    stop = true;
  }
});

(Ceci doit être testé pour vérifier si la sémantique de référence correcte pour la fermeture est générée.)

Une approche plus avancée consisterait à créer votre propre méthode d’extension permettant au délégué de renvoyer false pour arrêter la boucle:

static class MyExtensions {
  static void ForEachStoppable<T>(this IEnumerable<T> input, Func<T, bool> action) {
    foreach (T t in input) {
      if (!action(t)) {
        break;
      }
    }
  }
}
27
Richard

Avez-vous LINQ à votre disposition? Votre logique semble similaire à Any:

bool any = blackList.Any(s=>inputString.Contains(s));

qui est le même que:

bool any = blackList.Any(inputString.Contains);

Si vous n'avez pas LINQ, c'est toujours pareil que:

bool any = blackList.Find(inputString.Contains) != null;

Si vous voulez exécuter une logique supplémentaire, vous pouvez faire certaines choses (avec LINQ) avec TakeWhile etc.

15
Marc Gravell

Je ne pense pas qu'il y ait une manière élégante de le faire en utilisant la méthode ForEach. Une solution de hacky est de lancer une exception.

Qu'est-ce qui vous empêche de faire un foreach à l'ancienne?

foreach (string item in blackList)
{
    if (!inputString.Contains(item)) continue;

    result = true;
    break;
}
6
Michael Meadows

Si vous voulez une boucle, utilisez une boucle.

Action n'autorisant aucune valeur de retour, il est donc impossible que la fonction ForEach sache que vous voulez interrompre, à moins de lancer une exception. L'utilisation d'une exception ici est excessive.

3
Yuliy

La seule façon de "sortir" de la boucle est de lancer une exception. Il n’existe pas de style "break" permettant de quitter la méthode .ForEach, à la manière d’une boucle foreach normale.

2
JaredPar

La méthode ForEach n'est pas censée le faire. Si vous voulez savoir si une collection contient un élément, utilisez la méthode Contains. Et si vous souhaitez vérifier tous les éléments d'une collection, essayez la méthode N'importe quelle extension.

2
Rune Grimstad

si vous voulez vraiment exister une boucle foreach dans une liste, vous pouvez utiliser l'exception comme ce code:

public class ExitMyForEachListException : Exception
{
    public ExitMyForEachListException(string message)
        : base(message)
    {
    }
}
class Program
{
    static void Main(string[] args)
    {
        List<string> str = new List<string>() { "Name1", "name2", "name3", "name4", "name5", "name6", "name7" };
        try
        {
            str.ForEach(z =>
            {
                if (z.EndsWith("6"))
                    throw new ExitMyForEachListException("I get Out because I found name number 6!");
                System.Console.WriteLine(z);
            });
        }
        catch (ExitMyForEachListException ex)
        {
            System.Console.WriteLine(ex.Message);
        }

        System.Console.Read();
    }
}

espérons que cette aide obtiendra un autre point de vue.

1
Ricardo Figueiredo
    class Program
{
    static void Main(string[] args)
    {
        List<string> blackList = new List<string>(new[] { "jaime", "jhon", "febres", "velez" });
        string inputString = "febres";
        bool result = false;
        blackList.ForEach((item) =>
                              {
                                  Console.WriteLine("Executing");
                                  if (inputString.Contains(item))
                                  {
                                      result = true;
                                      Console.WriteLine("Founded!");
                                  }
                              },
                          () => result);
        Console.WriteLine(result);
        Console.ReadLine();
    }


}
public static class MyExtensions
{
    public static void ForEach<T>(this IEnumerable<T> enumerable, Action<T> action, Func<bool> breakOn)
    {
        foreach (var item in enumerable)
        {
            action(item);
            if (breakOn())
            {
                break;
            }
        }
    }
}
1
Jaime Febres
bool @break = false;

blackList.ForEach(item =>
 {  
    if(!@break && inputString.Contains(item))
     { @break = true;
       result = true;
     }

    if (@break) return;
    /* ... */
 });

Notez que ce qui précède itérera toujours dans chaque élément mais reviendra immédiatement. Bien sûr, cette méthode n’est probablement pas aussi efficace qu’un comportement normalforeach.

1
Mark Cidade

Est-ce que cela fonctionnerait pour vous:

bool result = null != blackList.Find( item => inputString.Contains(item)) );
0