user933
user933

Reputation: 69

Is there a way to refactor this event handling code in C#

I'm trying to refactor some code that looks like this (there are several other cases).

switch (input) {
    case "1":
         _service.getWCFStuff1Completed += new EventHandler<getWCFStuff1CompletedEventArgs>(method1);
         _service.getWCFStuff1Async(strSomething);
    case "2":
         _service.getWCFStuff2Completed += new EventHandler<getWCFStuff2CompletedEventArgs>(method2);
         _service.getWCFStuff2Async(strSomething);
    [etc...]
}

I'd like to change the code to something like this but I don't see any way to get a templated type (i.e. the EventArgs event handler) into an Action.

var Map = new Dictionary<string, Action<???, string>> {
    { "1", method1},
    { "2", method2}
};

Is there any way to do this, or another approach in which I can use a Dictionary and be able to write code something like:

Map[input](something-with-eventargs, strSomething);

Upvotes: 1

Views: 402

Answers (2)

Jan Van Herck
Jan Van Herck

Reputation: 2284

Does your Action even need to be typed? Can't you do something like this?

var map = new Dictionary<string, Action>();
map["1"] = () =>
{
    _service.getWCFStuff1Completed += 
        new EventHandler<getWCFStuff1CompletedEventArgs>(method1);
    _service.getWCFStuff1Async(strSomething);
};
map["2"] = () =>
{
    _service.getWCFStuff2Completed += 
        new EventHandler<getWCFStuff2CompletedEventArgs>(method2);
    _service.getWCFStuff2Async(strSomething);
};

Upvotes: 0

horgh
horgh

Reputation: 18534

I failed to find the way to make compiler infer EventHandler parameter type, but here are my thoughts:

Suppose we have a service (just to test):

public class Service
{
    public event EventHandler<MouseEventArgs> fooEvent1 = delegate { };
    public event EventHandler<KeyEventArgs> fooEvent2 = delegate { };

    public void Fire()
    {
        fooEvent1(null, null);
        fooEvent2(null, null);
    }
}

Consider this generic class:

class Map<T> where T : EventArgs
{
    Dictionary<string, EventHandler<T>> map;

    public Map()
    {
        map = new Dictionary<string, EventHandler<T>>();
    }

    public EventHandler<T> this[string key]
    {
        get
        {
            return map[key];
        }
        set
        {
            map[key] = value;
        }
    }
}

It maps a string to an EventHandler<T>. Obviously we'll have different classes for different T. To manage them let's take the following static class:

static class Map
{
    static Dictionary<Type, object> maps = new Dictionary<Type, object>();
    public static Map<U> Get<U>() where U : EventArgs
    {
        Type t = typeof(U);
        if (!maps.ContainsKey(t))
            maps[t] = new Map<U>();
        Map<U> map = (Map<U>)maps[t];
        return map;
    }
}

Now we can use it as follows:

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();

        Map.Get<MouseEventArgs>()["1"] = Form1_fooEvent1;
        Map.Get<KeyEventArgs>()["2"] = Form1_fooEvent2;

        Service s = new Service();
        s.fooEvent1 += Map.Get<MouseEventArgs>()["1"];
        s.fooEvent2 += Map.Get<KeyEventArgs>()["2"];
        s.Fire();
    }

    void Form1_fooEvent2(object sender, KeyEventArgs e)
    {
        textBox2.Text = "Form1_fooEvent2";
    }

    void Form1_fooEvent1(object sender, MouseEventArgs e)
    {
        textBox1.Text = "Form1_fooEvent1";
    }
}

Upvotes: 1

Related Questions