Как изменить тип значения в штучной упаковке внутри метода - PullRequest
0 голосов
/ 12 ноября 2008

Я пытаюсь создать библиотеку для упрощения вызовов позднего связывания в C #, и у меня возникают проблемы с опорными параметрами. У меня есть следующий метод, чтобы добавить параметр, используемый в вызове метода

    public IInvoker AddParameter(ref object value)
    {
        //List<object> _parameters = new List<object>();
        _parameters.Add(value);          

        //List<bool> _isRef = new List<bool>();
        _isRef.Add(true);

        return this;
    }

И это не работает с типами значений, потому что они упаковываются как объекты, поэтому они не модифицируются. Например:

int param1 = 2;
object paramObj = param1;
//MulFiveRef method multiplies the integer passed as a reference parameter by 5:
//void MulFiveRef(ref int value) { value *= 5; }
fi.Method("MulFiveRef").AddParameter(ref paramObj);

Это не работает. Вызов позднего связывания успешен, и внутренний список, содержащий параметры (_parameters), изменяется, но не значение вне вызова.

Кто-нибудь знает простой способ преодолеть это ограничение? Сигнатура AddParameter не может быть изменена, так как при поздних связывающих вызовах вы не можете заранее знать тип параметров (и так или иначе вы вставляете все параметры для вызова в массив объектов перед выполнением вызова)

Заранее спасибо.

Ответы [ 3 ]

1 голос
/ 12 ноября 2008

Если значение изменяется внутри метода , вам нужно будет объявить переменную temp (object) для передачи (ref) в метод, а затем самостоятельно распаковать ее:

    int i = 3;
    //...
    object obj = i;
    Foo(ref obj);
    i = (int)obj;

Обратите внимание, что это не позволит вам обновить значение после события. Нечто подобное событию или обратному вызову может быть альтернативным способом передачи изменений вызывающей стороне.

Обратите также внимание, что в C # 4.0 есть некоторые хитрости, которые помогут с этим только в контексте вызовов COM (где ref object так часто встречается [плюс, конечно, dynamic для позднего связывания, как отмечает Джон ]).

1 голос
/ 12 ноября 2008

Ваш метод в любом случае не меняется value - почему вы передаете его по ссылке? Это может иметь смысл, но это не совсем понятно для меня. Обратите внимание, что предоставленный вами пример кода не будет компилироваться в любом случае, так как ref аргументы должны быть точно того же типа, что и параметр.

(Кроме того, знаете ли вы, что C # 4.0 и .NET 4.0 будут иметь встроенную поддержку позднего связывания? Скорее всего, языковая версия будет проще в использовании, чем версия для библиотеки. Вы уверены, что в этот момент стоит потратить время на библиотеку?)

РЕДАКТИРОВАТЬ: Код, который вы предоставили, действительно не скомпилируется. Вы не получаете бокс для ref параметров, именно потому, что аргументы и типы параметров должны быть абсолютно одинаковыми. Вот пример кода, чтобы доказать это:

public class Test
{
    static void Main()
    {
        int i;
        Foo(ref i); // Won't compile - error CS1502/1503
    }

    static void Foo(ref object x)
    {
    }
}

Если ваш текущий код компилируется , то это не тот код, который вы указали в вопросе. Возможно, у вас есть другая перегрузка для AddParameter, которая принимает ref int?

0 голосов
/ 12 ноября 2008

Хорошо, благодаря исправлениям Джона Скита и кода Марка Гравелла, я разработал этот интерфейс:

        //This will be created with a factory
        IOperationInvoker invoker = new OperationInvoker(Activator.CreateInstance<MyLateBindingTestType>());

        int param1 = 2;
        object paramObj = param1;

        invoker.AddParameter(ref paramObj).Invoke("MulFiveRef");

        param1 = (int)invoker.Parameters[0];

Не совсем так, как я себе представлял, но он намного проще и удобочитаемее, чем мой предыдущий интерфейс:

        IOperationInvoker invoker = new OperationInvoker(Activator.CreateInstance<MyLateBindingTestType>());
        int refValue = 10;
        object[] args = Args.Build(refValue);

        invoker.Call("MulFiveRef", Args.ByRefIndexs(0), args);

        refValue = (int)args[0];

Большое спасибо за помощь людям:)

...