Как изменить тип значения в штучной упаковке внутри метода

StackOverflow https://stackoverflow.com/questions/283492

  •  08-07-2019
  •  | 
  •  

Вопрос

Я пытаюсь создать библиотеку для упрощения вызовов позднего связывания в 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 не может быть изменена, так как при поздних связывающих вызовах вы не можете заранее знать тип параметров (и так или иначе вы вставляете все параметры для вызова внутри массива объектов до выполнения вызова)

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

Это было полезно?

Решение

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

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

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

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

Другие советы

Ваш метод все равно не меняет 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 ?

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

        //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];

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top