通常のループでは、breakを使用してループから抜けることができます。匿名デリゲートを使用しても同じことができますか?
InputStringとresultの例は両方ともデリゲートの外部で宣言されています。
blackList.ForEach(new Action<string>(
delegate(string item)
{
if(inputString.Contains(item)==true)
{
result = true;
// I want to break here
}
}
));
編集:返信ありがとう、私は実際にジョンの瞬間にあなたの本を読んでいます:)記録のために、私はこの問題を見つけ、通常のforeachループに切り替えましたが、私は何かを逃したかどうかを確認するためにこの質問を投稿しました。
他の人が投稿したように、ForEachでループを終了することはできません。
LINQを使用できますか?その場合、TakeWhileとカスタムのForEach拡張メソッドを簡単に組み合わせることができます(最近ではほとんどすべてのプロジェクトにあるようです)。
ただし、あなたの例では、 List<T>.FindIndex
が最良の代替手段になりますが、実際にそれを行っていない場合は、reallyがやりたいことの例を投稿してください。
アクセスできるループはなく、そこから中断することもできません。 (匿名)デリゲートへの各呼び出しは新しい関数呼び出しであるため、ローカル変数は役に立ちません。しかし、C#はクロージャを提供するため、フラグを設定して、その後の呼び出しでは何も実行できません。
bool stop = false;
myList.ForEach((a) => {
if (stop) {
return;
} else if (a.SomeCondition()) {
stop = true;
}
});
(これは、クロージャーの正しい参照セマンティクスが生成されるかどうかを確認するためにテストする必要があります。)
より高度なアプローチは、ループを停止するためにデリゲートがfalseを返すことを可能にする独自の拡張メソッドを作成することです。
static class MyExtensions {
static void ForEachStoppable<T>(this IEnumerable<T> input, Func<T, bool> action) {
foreach (T t in input) {
if (!action(t)) {
break;
}
}
}
}
LINQを利用できますか?あなたのロジックはAnyに似ているようです:
bool any = blackList.Any(s=>inputString.Contains(s));
次と同じです:
bool any = blackList.Any(inputString.Contains);
LINQがない場合、これは次と同じです:
bool any = blackList.Find(inputString.Contains) != null;
追加のロジックを実行する場合は、TakeWhile
などを使用して(LINQを使用して)できることがあります。
ForEachメソッドを使用する場合、エレガントな方法はないと思います。ハックな解決策は、例外をスローすることです。
昔ながらのforeachをするのを妨げているのは何ですか?
foreach (string item in blackList)
{
if (!inputString.Contains(item)) continue;
result = true;
break;
}
ループが必要な場合は、ループを使用します。
Action
は戻り値を許可しないため、例外をスローするまで、ForEach関数がブレークしたいことを知る方法はありません。ここで例外を使用すると過剰になります。
ループを「終了」する唯一の方法は、例外をスローすることです。通常のforeachループのように.ForEachメソッドを終了する「ブレーク」スタイルの方法はありません。
ForEachメソッドは、これを行うことを意味しません。コレクションにアイテムが含まれているかどうかを知りたい場合は、Containsメソッドを使用する必要があります。コレクション内のすべてのアイテムのチェックを実行する場合は、任意の拡張方法を試してください。
リストにループforeachを本当に存在させたい場合は、次のコードのような例外を使用できます。
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();
}
}
この助けが他の視点を得るのを願っています。
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;
}
}
}
}
bool @break = false;
blackList.ForEach(item =>
{
if(!@break && inputString.Contains(item))
{ @break = true;
result = true;
}
if (@break) return;
/* ... */
});
上記は各アイテムを繰り返し処理しますが、すぐに戻ることに注意してください。もちろん、この方法は通常のforeach
ほど良くないでしょう。
これはあなたのために働くでしょうか:
bool result = null != blackList.Find( item => inputString.Contains(item)) );