15

LINQ シーケンスを処理しているときに、foreach ループを避けて、void を返すメソッドに各項目を送信したいことがよくあります。ただし、これを行うためのエレガントな方法は見つかりませんでした。今日、私は次のコードを書きました:

    private StreamWriter _sw;
    private void streamToFile(List<ErrorEntry> errors)
    {
        if (_sw == null)
        {
            _sw = new StreamWriter(Path.Combine
                                    (Path.GetDirectoryName(_targetDatabasePath), "errors.txt"));
        }

        Func<ErrorEntry, bool> writeSelector = 
            (e) => { _sw.WriteLine(getTabDelimititedLine(e)); return true; };

        errors.Select(writeSelector);

        _sw.Flush();
    }

ご覧のとおり、true を返すだけのラムダ関数を作成すると、Select メソッドがブール値のシーケンスを返すことがわかりました。そのシーケンスは無視します。ただし、これは少しお粗末でジャンクのようです。これを行うエレガントな方法はありますか?それとも、LINQ を誤って適用しているだけですか?

ありがとう。

4

2 に答える 2

19

まず第一に、現在のコードは機能しません。
Select、および他のほとんどの LINQ メソッドは遅延実行を使用します。つまり、結果を列挙するまで実際には何もしません。

一般に、LINQ クエリで副作用のあるラムダを使用しないでください。

あなたの質問に答えるには、foreachループを使用する必要があります。

ForEach拡張メソッドを探しています。Eric Lippert が、Microsoft がこれを書かなかった理由を説明します

本当にしたい場合は、自分で書くことができます:

public static void ForEach<T>(this IEnumerable<T> sequence, Action<T> action) {
    if (sequence == null) throw new ArgumentNullException("sequence");
    if (action == null) throw new ArgumentNullException("action");
    foreach(T item in sequence) 
        action(item);
}

//Return false to stop the loop
public static void ForEach<T>(this IEnumerable<T> sequence, Func<T, bool> action) {
    if (sequence == null) throw new ArgumentNullException("sequence");
    if (action == null) throw new ArgumentNullException("action");

    foreach(T item in sequence) 
        if (!action(item))
            return;
}
于 2010-03-12T02:06:20.813 に答える
6

一般的なコンセンサスは、LINQ はクエリと選択のためのものであり、ループと反復には従来の反復メソッドを使用するというものです。

これは言いたくないのですが、linq クエリを実行したいので、従来の foreach ループを使用し、結果の IEnumerable を反復処理します。コードの可読性に役立ちます。LINQ には中毒性があることは認めます。ラムダと遅延実行を使用してすべてを実行したいが、ループは従来の C# ループ メソッドに任せる必要があります。これは間違いなく副作用に役立ちます。

于 2010-03-12T14:11:03.043 に答える