17

foreach拡張メソッドから抜け出す方法はありますか?「break」キーワードは、拡張メソッドをブレーク元の有効なスコープとして認識しません。

//Doesn't compile
Enumerable.Range(0, 10).ToList().ForEach(i => { System.Windows.MessageBox.Show(i.ToString()); if (i > 2)break; });

編集:質問から「linq」を削除


コードは、拡張メソッドでブレークが機能しないことを示す単なる例であることに注意してください...本当に私が欲しいのは、ユーザーがリストの処理を中止できるようにすることです。UIスレッドには中止変数があり、forループはちょうどブレークします。ユーザーがキャンセルボタンを押したとき。現在、通常のforループがありますが、extensionメソッドで実行できるかどうかを確認したいと思いました。

4

8 に答える 8

20

これをList<T>ForeachとLINQと呼ぶ方がおそらく正確です。

どちらの場合でも、このループから抜け出す方法はありません。これは主に、実際にはループではないためです。これは、ループ内で呼び出されるデリゲートを受け取るメソッドです。

ただし、ブレーク機能を備えたForEachの作成はかなり簡単です。

public delegate void ForEachAction<T>(T value, ref bool doBreak);
public static void ForEach<T>(this IEnumerable<T> enumerable, ForEachAction<T> action) {
    var doBreak = false;
    foreach (var cur in enumerable) {
        action(cur, ref doBreak);
        if (doBreak) {
            break;
        }
    }
}

その後、次のようにコードを書き直すことができます

Enumerable.Range(0,10)
    .ForEach((int i,ref bool doBreak) => {
        System.Windows.MessageBox.Show(i.ToString()); 
        if ( i > 2) {doBreak = true;}
    });
于 2010-06-29T23:42:17.350 に答える
11

TakeWhileの使用をお勧めします。

Enumerable.Range(0, 10).TakeWhile(i => i <= 2).ToList().ForEach(i => MessageBox.Show(i.ToString()));

または、Rxを使用します:

Enumerable.Range(0, 10).TakeWhile(i => i <= 2).Run(i => MessageBox.Show(i.ToString()));
于 2010-06-29T23:58:46.343 に答える
3

使ってみませんWhereか?

Enumerable.Range(0, 10).Where(i => i <= 2).ToList().ForEach(...)
于 2010-06-29T23:58:16.460 に答える
1

「break」の代わりに「return」ステートメントを試してください。これはデリゲート関数であり、実際のループではありません。

試す:

Enumerable.Range(0, 10).ToList().ForEach(i => { System.Windows.MessageBox.Show(i.ToString()); if (i > 2) return; });
于 2014-12-20T00:13:33.857 に答える
0

使ってみませんforeachか?..。

PS:冗談ですが、あなたが言ったように、Linqでそれを行う方法を試してみるという考えを理解しています(そして同じ理由でここでグーグルで検索しました)...プロダクションコードのメンテナンス/準備の理由から、単純なforeachもので十分だと思います時折。

于 2013-01-25T09:30:16.113 に答える
0

私自身は、Linq Select+FirstOrDefaultを使用しました。リスト内の「each」を変換しますが、Firstを要求しているため、一致する最初のものを見つけた後、変換を停止します。

var thingOption = list.Select(thing => AsThingOption(thing))
.FirstOrDefault(option => option.HasValue) ?? Option.None<MyThing>;

ご覧のとおり、私はそれぞれをOptionに変換しており、メソッドAsThingOptionは変換に成功する可能性があり、変換が完了すると、リストの反復処理を停止します。AsThingOptionメソッド内の条件が変換に成功しない場合、最終結果はNoneになります。

お役に立てば幸いです。

于 2017-04-18T21:08:44.023 に答える
0

throw new Exception("Specific message")ブールフラグを使用しないのはなぜですか?

DataTable dt = new DataTable();
bool error = false;

try
{
    dt.AsEnumerable().ToList().ForEach(dr =>
    {
        if (dr["Col1"].ToString() == "")
        {
            error = true;
            throw new Exception("Specific message");
        }
        else 
            // Do something
    });
}
catch (Exception ex)
{
    if (ex.Message == "Specific message" || error) 
        // do something
    else
        throw ex;
}
于 2017-06-20T00:38:46.337 に答える
0

条件がfalseになるまでアクションをループする必要があり、各アクションで条件の追跡に使用される値を変更できる場合があります。この.TakeWhile()のバリエーションを思いつきました。ここでの利点は、リスト内の各アイテムが何らかのロジックに参加できることです。その後、アイテムに直接関係しない条件でループを中止できます。

new List<Action> {
    Func1,
    Func2
}.TakeWhile(action => {
    action();
    return _canContinue;
});
于 2017-06-28T19:48:33.760 に答える