Sending items in a LINQ sequence to a method that returns void

人盡茶涼 提交于 2019-12-22 03:35:24

问题


Often while I'm dealing with LINQ sequences, I want to send each item to a method returning void, avoiding a foreach loop. However, I haven't found an elegant way to do this. Today, I wrote the following code:

    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();
    }

As you can see, I write a lambda function that just returns true, and I realize that the Select method will return a sequence of booleans- I'll just ignore that sequence. However, this seems a little bit noobish and jank. Is there any elegant way to do this? Or am I just misapplying LINQ?

Thanks.


回答1:


First of all, your current code will not work.
Select, and most other LINQ methods, use deferred execution, meaning that they don't actually do anything until you enumerate the results.

In general, you should never use a lambda with side effects in a LINQ query.

To answer your question, you should use a foreach loop.

You're looking for a ForEach extension method; Eric Lippert explains why Microsoft didn't write one.

If you really want to, you can write one yourself:

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;
}



回答2:


The common consensus is that LINQ is for querying and selection... while you use traditional iterative methods for looping and iteration.

I hate to say this but you would use a traditional foreach loop because you want your linq queries to execute, and you iterate over the resulting IEnumerable. It helps with code readability, and I will admit LINQ is addictive. You want to do everything using Lambdas and deferred execution, but looping should be left to your traditional C# looping methods. This will definitely help with side-effects.



来源:https://stackoverflow.com/questions/2430033/sending-items-in-a-linq-sequence-to-a-method-that-returns-void

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!