8

Is there a workaround to update a ref parameter inside an anonymous method?

I know that the an anonymous method doesn't allow access to ref parameters of the outer scope, but is there another way to do it? I am using an external library for the MessageStream so cannot alter the arguments of the delegate...

void DoWork(ref int count)
{
    MessageStream Stream = new MessageStream();
    Stream.MessageReceived += (o, args) =>
    {
        //Error cannot use ref or out parameter inside anonymous method
        count++;
    };
}
John Saunders
  • 160,644
  • 26
  • 247
  • 397
jamos
  • 213
  • 2
  • 8
  • The answer depends on whether you can be sure the `Stream.MessageReceived` will be raised before `DoWork` returns. Can you be sure of that? –  May 13 '14 at 12:07
  • do you know unsafe context? If no I post an answer with this solution – faby May 13 '14 at 12:07
  • @faby I think I know what you're thinking of, and if I'm right, that won't work. It will *usually* work, but it will sometimes fail, and there is no way to fix it so that it always works. –  May 13 '14 at 12:09
  • Why do you have `ref` on that parameter? Are you sure you need it? It's very rare to see it being used. If you can show us more about how this is used, we might be able to suggest another way that'll work right. – Tim S. May 13 '14 at 12:10
  • @hvd I kmow yes this is the problem with unasafe context – faby May 13 '14 at 12:12
  • @faby Unsafe code is not inherently broken. There is plenty of correct and useful unsafe code. But you have to make sure you are aware of what the language and runtime guarantee, and what they don't. If you're not, you won't get a nice warning telling you what you're doing wrong, it can fail in the most spectacular ways imaginable. –  May 13 '14 at 12:14
  • I'm not sure I want to go down the unsafe context road. It sounds like it will cause me more problems. – jamos May 13 '14 at 12:29

2 Answers2

5

In your case there is no viable work-around to this problem: by the time the Stream.MessageReceived event fires, the count may be well out of scope in the caller of your DoWork function.

In situations like that you should encapsulate the count in an object, and keep a reference to that object in both the event handler and in the caller, like this:

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();
    };
}
Alberto
  • 15,626
  • 9
  • 43
  • 56
Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
  • Possibly Interlocked.Increment might be sensible here, depending on usage. – Paddy May 13 '14 at 12:28
  • I think this is the only way I can achieve it. A bit of code re-jigging in order. I was hoping it would all play nice somehow. – jamos May 13 '14 at 12:31
1

If you want to have the delegate update a variable from an outter scope, pass a lambda that sets the value instead of passing the count by 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();
}
dcastro
  • 66,540
  • 21
  • 145
  • 155