c # используя Array.ForEach Action Predicate с массивом типа значения или строки - PullRequest
3 голосов
/ 18 февраля 2009

Правильно ли я считаю, что следующий фрагмент не работает (элементы массива не изменены) , поскольку массив имеет целочисленный тип значения.

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

То же самое применимо, если в примере используется массив строк, предположительно потому, что строка неизменна.

У меня есть вопрос: -

Есть ли способ обойти это? Я не могу изменить сигнатуру метода обратного вызова - например, добавив ключевое слово ref, и я не хочу оборачивать тип значения классом - который будет работать ...

(Конечно, я мог бы просто написать для этого старомодный цикл foreach!)

Ответы [ 4 ]

9 голосов
/ 18 февраля 2009

Вы просто меняете локальную переменную, а не элемент в списке. Для этого вы хотите ConvertAll, который создает новый список / массив:

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

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

с:

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

Это также можно записать анонимным методом:

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

Или в C # 3.0 как лямбда:

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

Кроме этого ... цикл for:

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

Но, так или иначе, вам придется получить значение из вашего метода. Если вы не измените подпись, вы не сможете.

4 голосов
/ 18 февраля 2009

Метод Array.ForEach () не позволит вам практически изменить его члены. Вы можете изменить его, используя LINQ, например

ints = ints.Select(x => x +10 ).ToArray();
0 голосов
/ 18 февраля 2009

Прежде всего, вообще опасно модифицировать коллекцию, над которой вы foreach обращаетесь. Большинство коллекций поддерживают внутренний «тег версии» для отслеживания изменений, поэтому перечислитель будет выдавать исключение, когда попытается выполнить итерацию по измененной коллекции.

Что касается вашего вопроса, вы не сможете сделать это с типами значений и Array.ForEach. Используйте foreach или Convert, чтобы делать то, что вы хотите.

0 голосов
/ 18 февраля 2009

foreach - единственный способ, типы значений в массивах и списках всегда копируются, поэтому их изменение не будет работать, если только вы не сохраните измененное значение обратно. Метод AddTen этого не делает, он изменяет свою собственную копию.

...