List<T>.ForEach with index

LINQ doesn't have a ForEach method, and for good reason. LINQ is for performing queries. It is designed to get information from some data source. It is not designed to mutate data sources. LINQ queries shouldn't cause side effects, which is exactly what you're doing here.

The List class does have a ForEach method, which is what you are using. Because it's not actually in the System.Linq namespace it's not technically a part of LINQ.

There is nothing wrong with the for loop in your question. It would be wrong (from a good practice perspective) to try to change it in the way that you're trying to.

Here is a link that discusses the matter in more detail.

Now, if you want to ignore that advice and use a ForEach method anyway, it's not hard to write one that provides an index to the action:

public static void ForEach<T>(this IEnumerable<T> sequence, Action<int, T> action)
{
    // argument null checking omitted
    int i = 0;
    foreach (T item in sequence)
    {
        action(i, item);
        i++;
    }
}

If you really want to use a List.ForEach, it's simple:

//[...]
int i=0;
donations.ForEach(x => nvc.Add("item_name_" + i++, x.AccountName);

It's a little convoluted and creates an intermediate collection, but how about:

donations.Select((x, i) => new {Name = "item_name_" + i, x.AccountName})
    .ToList()
    .ForEach(x=> nvc.Add(x.Name, x.AccountName));

This uses the overload of Enumerable.Select which incorporates the index.

I do have to argue there is nothing really to gain from doing it this way. You create more overhead with the intermediate collection and IMHO lose readability over your original for-loop.

You can also skip the intermediate collection if you're willing to use foreach loop instead of List.ForEach. See @wageoghe's answer (again highly recommended).

Tags:

C#

Linq

Generics