Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there any way to create indexed events in C# (or some workaround)?

Tags:

c#

events

The caption is confusing. Let me clarify a bit:

I'd like to provide events that depend on a parameter so an observer can decide to receive events if something happens to a specific "id". It could look like this:

public event EventHandler Foo (string id);

I'm aware that this syntax is wrong in .NET 3.5, and I'm also aware that this idea introduces additional problem (for instance, how do we manage unsubscription?).

How should I circumvent this issue? I thought about using something like:

public EventHandler Foo (string id);

which is at least legal syntax and could work, but it still does not look very great to me.

Edit: I'm not asking about passing arguments to the callback function. My idea is more like this:

class Bleh
{
    public event EventHandler Foo (string index);

    private void RaiseEvents() // this is called by a timer or whatever
    {
        Foo["asdf"] (this, EventArgs.Empty); // raises event for all subscribers of Foo with a parameter of "asdf"
        Foo["97"] (this, EventArgs.Empty); // same for all "97"-subscribers
        // above syntax is pure fiction, obviously
    }
}

// subscribe for asdf events via:
Bleh x = new Bleh ();
x.Foo["asdf"] += (s, e) => {};

Explanation
Since you're probably wondering why I try to do this, I'll explain my situation. I've got a class that provides positions of certain objects (each of these identified by some ID string).

Instead of providing an event EventHandler<PositionChangedEventArgs> that is raised for ANY positional changes, I'd like to have an event for every object (accessed by an index), so observers can listen to the events for a specific ID only.

like image 978
mafu Avatar asked Feb 10 '10 15:02

mafu


2 Answers

You could do something like this:

public class Foo
{
    public class Bar
    {
        public event EventHandler PositionChanged;

        internal void RaisePositionChanged()
        {
            var handler = PositionChanged;
            if (handler != null)
                handler(this, EventArgs.Empty);
        }
    }

    private Dictionary<string, Bar> m_objects;

    public Bar this[string id]
    {
        get
        {
            if (!m_objects.ContainsKey(id))
                m_objects.Add(id, new Bar());

            return m_objects[id];
        }
    }

    private void RaisePositionChanged(string id)
    {
        Bar bar;
        if (m_objects.TryGetValue(id, out bar))
            bar.RaisePositionChanged();
    }
}

Then to subscribe an event, it would be as simple as this:

Foo foo = new Foo();

foo["anId"].PositionChanged += YourHandler;
like image 168
Jeff Cyr Avatar answered Oct 24 '22 17:10

Jeff Cyr


You need to use an EventArgs-derived class which includes the ID, and then use EventHandler<IdEventArgs> or whatever:

public class IdEventArgs : EventArgs
{
    private readonly string id;
    public string Id { get { return id; } }

    public IdEventArgs(string id)
    {
        this.id = id;
    }
}

public event Eventhandler<IdEventArgs> Foo;

When you raise the event you'll need to create an instance of IdEventArgs, and then the subscriber can examine that and decide what to do with it.

like image 22
Jon Skeet Avatar answered Oct 24 '22 18:10

Jon Skeet