views:

445

answers:

3

Im trying to write to an API and I need to call an eventhandler when I get data from a table. Something like this:

    public override bool Run(Company.API api)
    {
        SomeInfo _someInfo = new SomeInfo();

        if (_someInfo.Results == 1)
            return true;
        else
            return false;

        using (MyTable table = new MyTable(api))
        {
            table.WhenData += new EventHandler<DataEventArgs<Record>>(table_WhenData);
            table.WhenDead += new EventHandler<EventArgs>(table_WhenDead);
            table.Start();
        }

    public void table_WhenData(object sender, DataEventArgs<Record> e)
    {
        return true;
    }

The problem that Im having is I dont know how to pass a return value back from table_WhenData to the Run method.

Ive tried many ways (like trying to pass _someInfo to the method) but I just cant seem to get the syntax right.

Any suggestion is greatly appreciated.

+3  A: 

The common pattern here is not to return any data from the event handler, but to add properties to your event argument object so that the consumer of the event can set the properties which the caller would then have access to. This is very common in UI handling code you see the Cancel event concept all over the place.

The following is psuedo code, and not compile ready. But its intent is to show the pattern not be syntactically correct.

public MyEventArgs : EventArgument
{
   public bool Cancel{get;set;}
}

public bool fireEvent()
{
    MyEventArgs e=new MyEventArgs();

    //Don't forget a null check, assume this is an event
    FireEventHandler(this,e);

    return e.Cancel;
}

public HandleFireEvent(object sender, MyEventArgs e)
{
 e.Cancel=true;
}

Edit

I like how Jon Skeet worded this, make the EventArguments mutuable. That is the consumer of the event can modify the state of the Event Argument object allowing for the raiser of the event to get to that data.

JoshBerke
+4  A: 

The only way you can do it is to make one of the arguments (preferably the "args" rather than the sender) mutable. If it's not already mutable, you've basically got problems - there's just no way of getting the information out.

(Okay, there's one way - you can keep the event argument itself immutable, but make one member of it a method which ends up calling a delegate registered by the code raising the event in the first place. But that's horrible...)

Jon Skeet
My head hurts trying to understand the one way please make the EventArgs mutuable!
JoshBerke
What about using a closure as described in my response?
Igor ostrovsky
Igor: That would work, but usually the bit of code which needs the result isn't the bit of code subscribing to the event.
Jon Skeet
+1  A: 

A simple solution is to use a closure:

public override bool Run() {
    SomeInfo someInfo = ...
    table.WhenData += (obj, args) => {
        someInfo.Return = something
    };
}
Igor ostrovsky
the concern I might have with this solution, is the concurrency issues. One thread calling the event, another reading the someInfo variable before the write has completed. It would need multi-thread protection of some sort.
simon