Обновить параметр ref внутри анонимного метода

Есть ли обходной путь для обновления параметра ref внутри анонимного метода?

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

void DoWork(ref int count)
{
    MessageStream Stream = new MessageStream();
    Stream.MessageReceived += (o, args) =>
    {
        //Error cannot use ref or out parameter inside anonymous method
        count++;
    };
}

person jamos    schedule 13.05.2014    source источник
comment
Ответ зависит от того, можете ли вы быть уверены, что Stream.MessageReceived будет поднят до того, как DoWork вернется. Вы можете быть в этом уверены?   -  person    schedule 13.05.2014
comment
Вы знаете небезопасный контекст? Если нет, я отправляю ответ с этим решением   -  person faby    schedule 13.05.2014
comment
@faby Думаю, я знаю, о чем ты думаешь, и если я прав, это не сработает. Обычно это будет работать, но иногда это будет давать сбой, и нет никакого способа исправить это, чтобы он всегда работал.   -  person    schedule 13.05.2014
comment
Почему у вас есть ref в этом параметре? Вы уверены, что вам это нужно? Очень редко можно увидеть его использование. Если вы можете показать нам больше о том, как это используется, мы могли бы предложить другой способ, который будет работать правильно.   -  person Tim S.    schedule 13.05.2014
comment
@hvd Я знаю, да, это проблема с небезопасным контекстом   -  person faby    schedule 13.05.2014
comment
@faby Небезопасный код по своей сути не сломан. Существует много правильного и полезного небезопасного кода. Но вы должны убедиться, что знаете, что гарантирует язык и среда выполнения, а что нет. Если нет, вы не получите приятного предупреждения о том, что вы делаете неправильно, это может привести к самым впечатляющим ошибкам, какие только можно себе представить.   -  person    schedule 13.05.2014
comment
Я не уверен, что хочу идти по дороге небезопасного контекста. Похоже, это доставит мне еще больше проблем.   -  person jamos    schedule 13.05.2014


Ответы (2)


В вашем случае нет жизнеспособного обходного пути для этой проблемы: к тому времени, когда срабатывает событие Stream.MessageReceived, count может выйти за рамки вызывающей стороны вашей функции DoWork.

В подобных ситуациях вы должны инкапсулировать count в объект и сохранить ссылку на этот объект как в обработчике событий, так и в вызывающей программе, например:

class Counter {
    public int Value {get;private set;}
    public void Increment() {Value++;}
}
void DoWork(Counter count) {
    MessageStream Stream = new MessageStream();
    Stream.MessageReceived += (o, args) => {
        count.Increment();
    };
}
person Sergey Kalinichenko    schedule 13.05.2014
comment
Возможно, Interlocked.Increment здесь может быть разумным, в зависимости от использования. - person Paddy; 13.05.2014
comment
Я думаю, что это единственный способ добиться этого. Небольшая переделка кода по порядку. Я надеялся, что все это как-то хорошо сыграет. - person jamos; 13.05.2014

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

//shared var
private static int _count = 0;

//call your method
DoWork(() => _count++);  //instead of DoWork(ref _count);


void DoWork(Action countInc)
{
    MessageStream Stream = new MessageStream();
    Stream.Activated += (o, args) => countInc();
}
person dcastro    schedule 13.05.2014