tags:

views:

5875

answers:

4

Hi, Am I correct in thinking the following snippet does not work (the array items are not modified) because the array is of integer which is value type.

class Program
{
    public static void Main()
    {
        int[] ints = new int[] { 1,2 };

        Array.ForEach(ints, new Action<int>(AddTen));

        // ints is not modified
    }
    static void AddTen(int i)
    {
        i+=10;
    }
}

The same would apply if the example used an array of string, presumably because string is immutable.

The question I have is:-

Is there a way around this? I can't change the signature of the callback method - for instance by adding the ref keyword and I don't want to wrap the value type with a class - which would work...

(Of course, I could simply write an old fashioned foreach loop to do this!)

+7  A: 

You are simply changing the local variable - not the item in the list. To do this, you want ConvertAll, which creates a new list/array:

    int[] ints = new int[] { 1,2 };

    int[] newArr = Array.ConvertAll<int,int>(ints, AddTen);

with:

static int AddTen(int i)
{
    return i+10;
}

This can also be written with an anonymous method:

int[] newArr = Array.ConvertAll<int,int>(ints,
    delegate (int i) { return i+ 10;});

Or in C# 3.0 as a lambda:

int[] newArr = Array.ConvertAll(ints, i=>i+10);

Other than that... a for loop:

for(int i = 0 ; i < arr.Length ; i++) {
    arr[i] = AddTen(arr[i]); // or more directly...
}

But one way or another, you are going to have to get a value out of your method. Unless you change the signature, you can't.

Marc Gravell
+1  A: 

The Array.ForEach() method won't let you practically modify it's members. You can modify it by using LINQ such as this

ints = ints.Select(x => x +10 ).ToArray();
JaredPar
Actually, Array.ConvertAll would do in this case (and is more efficient as the length is calculated correctly), but either would suffice.
Marc Gravell
@Marc, learn something new every day. Hadn't seen that method before. Thanks!
JaredPar
A: 

foreach is the only way, value types in arrays and lists are always copied and modifying them is therefore not going to work, unless you store the modified value back. The AddTen method isn't doing that, it modifies its own copy.

Frans Bouma
A: 

First off, it's generally dangerous to modify the collection you're foreaching over. Most collections maintain an internal "version tag" to keep track of changes, so enumerator will throw an exception when it will attemt to iterate over the modified collection.

As for your question, there's no way you can do that with values types and Array.ForEach. Use foreach or Convert to do what you want.

Anton Gogolev