Есть способ передать по ссылке, используя переменные параметры в C #? - PullRequest
4 голосов
/ 12 января 2009

Я хотел бы иметь функцию, которая изменяет некоторый список переменных параметров, но все они являются типами значений (int, string). Есть ли способ заставить ключевое слово params работать с ключевым словом ref или чем-то подобным?

public void funcParams(params object[] list)
{
   /* Make something here to change 'a', 'b' and 'c' */
}

public void testParams()
{
    int a = 1, b = 2, c = 3;

    funcParams(a, b, c);
}

Проблема в том, что я пытаюсь упростить свою жизнь, создав метод, который модифицирует поля объекта. Я делаю динамическую генерацию кода с использованием Cecil и стараюсь не писать слишком много кода, сгенерированного IL.

Для упрощения я хотел бы передать список полей по ссылке. Мне нужно перейти к функции, которая изменяет их, а не изменяет их путем генерации соответствующего IL. Некоторые параметры обнуляются и делают генерацию кода немного более болезненной. Создание некоторых методов перегрузки вместо params в этом случае не очень поможет.

Ответы [ 3 ]

8 голосов
/ 12 января 2009

Ну, вы можете объявить несколько перегрузок, т.е.

public void FuncParams(ref int a) {...}
public void FuncParams(ref int a, ref int b) {...}

и т.д.

В противном случае вам придется читать обратно из массива (поскольку params действительно означает «неявный массив»):

object[] args = {1,2,3};
funcParams(args);
Console.WriteLine(args[0]); // updated
Console.WriteLine(args[1]); // updated
Console.WriteLine(args[2]); // updated

(конечно, если он принимает только int с, было бы лучше использовать int[] во всем)

5 голосов
/ 12 января 2009

Да. Это возможно.

Однако полученный код является «небезопасным», что делает его непроверяемым.

Это может или не может быть проблемой в зависимости от ваших требований.

В любом случае, вот код:

using System;

namespace unsafeTest
{
    class MainClass
    {
        public static void Main(string[] args)
        {
            Console.WriteLine("Hello World!");
            unsafe 
            {       
                int x = 0;
                int y = 0;
                int z = 0;
                bar(&x, &y, &z);
                Console.WriteLine(x);
                Console.WriteLine(y);
                Console.WriteLine(z);
            }
        }

        unsafe static void bar(params int *[] pInts)
        {
            int i = 0;
            foreach (var pInt in pInts)
            {
                *pInt = i++;
            }
        }
    }
}
2 голосов
/ 12 января 2009

Нет, это невозможно с аккуратным синтаксисом. Внутренняя причина заключается в том, что среда выполнения рассматривает метод как простой метод, принимающий аргумент массива. Компилятор выполняет служебную работу по созданию массива и заполнению его указанными аргументами. Поскольку аргументы являются типами значений, они будут скопированы в массив, и любое изменение в них не повлияет на исходные переменные. Другие способы достижения этого не позволят достичь цели существования params, который является хорошим синтаксисом для переменного числа аргументов.

...