alan2here
alan2here

Reputation: 3317

whats up with this foreach in c#?

(edit: Slight tidy of the code.)

Using foreach like this works fine.

var a = new List<Vector2>();

a.ForEach(delegate(Vector2 b) {
    b.Normalize(); });

The following however causes "No overload for method 'ForEach' takes 1 arguments".

byte[,,] a = new byte[2, 10, 10];

a.ForEach(delegate(byte b) {
    b = 1; });

Upvotes: 5

Views: 1899

Answers (6)

Joshua Rodgers
Joshua Rodgers

Reputation: 5404

I would recommend you just use a normal foreach loop to transform the data. You're using a method that exists only on the List<T> implementation, but not on arrays.

Using a method for foreach really gains you nothing, unless for some reason you were wanting to do data mutation in a method chain. In that case, you may as well write your own extension method for IEnumerable<T>. I would recommend against that, though.

Having a separate foreach loop makes it clear to the reader that data mutation is occurring. It also removes the overhead of calling a delegate for each iteration of the loop. It will also work regardless of the collection type as long as it is an IEnumerable (not entirely true, you can write your own enumerators and enumerables, but that's a different question).

If you're looking to just do data transformations (i.e. projections and the like) then use LINQ.

Also keep in mind that with the array, you're getting a copy of the byte not a reference. You'll be modifying just that byte not the original. Here's an example with the output:

int[] numbers = new int[] { 1, 2, 3, 4, 5 };

Array.ForEach(numbers, number => number += 1);

foreach(int number in numbers)
{
    Console.WriteLine(number);
}

Which yields the output:

1 2 3 4 5

As you can see, the number += 1 in the lambda had no effect. In fact, if you tried this in a normal foreach loop, you would get a compiler error.

Upvotes: 3

Miguel Angelo
Miguel Angelo

Reputation: 24192

I don't know of a ForEach method that takes multi-dimensional arrays. If you want one, i think you will have to create it yourself.

Here is how to do it:

    private static void ForEach<T>(T[, ,] a, Action<T> action)
    {
        foreach (var item in a)
        {
            action(item);
        }
    }

Sample program, using the new ForEach method:

static class Program
{
    static void Main()
    {
        byte[, ,] a = new byte[2, 10, 10];

        ForEach(a, delegate(byte b)
        {
            Console.WriteLine(b);
        });
    }
    private static void ForEach<T>(T[, ,] a, Action<T> action)
    {
        foreach (var item in a)
        {
            action(item);
        }
    }
}

Also, the ForEach method in the Array version, is not an instance method, it is statis method. You call it like this:

Array.ForEach(array, delegate);

Upvotes: 1

Serge Wautier
Serge Wautier

Reputation: 21878

raw arrays have much less instance methods than generic collections because they are not templated. These methods, such as ForEach() or Sort() are usually implemented as static methods which are themselves templated.

In this case, Array.Foreach(a, action) will do the trick for the array.

Of course, the classical foreach(var b in a) would work for both List and Array since it only requires an enumerator.

However:

  1. I'm not sure how you'd loop over a multidimensional array.
  2. Your assignment (b=1) won't work. Because you receive a value, not a reference.

Upvotes: 0

sll
sll

Reputation: 62504

You've used syntax of List.ForEach() method for the array, but Array.ForEach() syntax is:

public static void ForEach<T>(
    T[] array,
    Action<T> action
)

One important point that array should be one-dimensional in order to use it in Array.ForEach(). Considering this I would suggest using simple for loop

// first dimension
for (int index = 0; index < bytesArray.GetLength(0); index++)             

// second dimension
for (int index = 0; index < bytesArray.GetLength(1); index++)             

// third dimension
for (int index = 0; index < bytesArray.GetLength(2); index++)             

Upvotes: 1

Matthew Flaschen
Matthew Flaschen

Reputation: 284796

List has the first instance method. Arrays do not.

Upvotes: 0

Austin Salonen
Austin Salonen

Reputation: 50215

You're using two different ForEach'es.

Array.ForEach in the byte[,,] example (though you're using it incorrectly) and List.ForEach in the List<...> example.

Upvotes: 2

Related Questions