0

Is it possible to create a switch-case statement around EventArgs?

ie.:

void MyMethod(object sender, EventArgs e)
{
    switch(e)
    {
        //MyEventArgs inherit from EventArgs
        case e is MyEventArgs:
            //Do some code...
            break;
        default:
            break;
    }
}

Right now I can't find a way to place it in a switch-case, so I'm using if-else statements, which will be slower than a switch-case when I fill many if-else's in it (since the switch-case is creating some kind of a hash-table of case's underneath the hood).

grmihel
  • 784
  • 3
  • 15
  • 40
  • 1
    You really won't notice any difference in speed. – Matthew Watson Nov 18 '14 at 14:34
  • Is your target to execute code only when a custom `EventArgs` object will be passed to your method? I mean... Is there any non-custom `EventArgs` object that requires some code execution in this case? – HuorSwords Nov 18 '14 at 14:40
  • 1
    Being in this kind of predicament in the first place usually indicates your design could be structured better. – Rotem Nov 18 '14 at 14:53

5 Answers5

4

You can't use switch in your scenario.

switch statement requires an integral type or string as parameter (more details below). You can't pass EventArgs as parameter to your switch statement, Also case statement requires a compile time constant value.

If you look at the C# 5.0 Specifications:

The governing type of a switch statement is established by the switch expression.

  • If the type of the switch expression is sbyte, byte, short, ushort, int, uint, long, ulong, bool, char, string, or an enum-type, or if it is the nullable type corresponding to one of these types, then that
    is the governing type of the switch statement.
  • Otherwise, exactly one user-defined implicit conversion (§6.4) must exist from the type of the switch expression to one of the following
    possible governing types: sbyte, byte, short, ushort, int, uint,
    long, ulong, char, string, or, a nullable type corresponding to one
    of those types.
  • Otherwise, if no such implicit conversion exists, or if more than one such implicit conversion exists, a compile-time error occurs.

The other issue in your code is the case statement:

switch C#

Each case label specifies a constant value.

Your case statement specifies a value which can't be determined at a compile time.

This leaves you with the option of using if-else block. Unless you are handling hundreds of types of EventArgs, it is highly unlikely that you will see any significant performance gain.

Habib
  • 219,104
  • 29
  • 407
  • 436
  • Thats making sense. I guess I'll leave it with a if-else statement for now. I'm only handling 4-5 different EventArgs atm but might be using more later. I guess that if I really want to put it in a switch-case, I could wrap the custom eventargs, and give it a Enum value to case on instead. But then a if-else would be more neat to use anyways. Thanks. – grmihel Nov 18 '14 at 16:24
  • @grmihel, also, as much as I remember, for number of cases below 5 in a switch statement, compiler doesn't create a lookup table. You may also think about re-designing your solution, since this looks like a code smell. – Habib Nov 18 '14 at 16:25
  • I'm not sure a redesign is neccesary. The method is catching up events, that then determine which response to send. Sure if the number of event increase drastic, I've have to break it into peices instead :) – grmihel Nov 18 '14 at 16:30
3

In switch case block each case must be evaluated statically. This means that you need a constant in each case. This post maybe useful also C# switch statement limitations - why?

Community
  • 1
  • 1
hatem87
  • 157
  • 4
1

You could try it with a Dictionary<Type, Action<EventArgs>>:

private static Dictionary<Type, Action<EventArgs>> _EventDispatcher;

static Program()
{
    _EventDispatcher = new Dictionary<Type, Action<EventArgs>>();
    _EventDispatcher.Add(typeof(EventArgs), OnEventArgs);
    _EventDispatcher.Add(typeof(MyEventArgs), OnMyEventArgs);
}

private static void MyMethod(object sender, EventArgs e)
{
    Action<EventArgs> eventMethod;

    if (!_EventDispatcher.TryGetValue(e.GetType(), out eventMethod))
        eventMethod = OnUnknownEventArgs;

    eventMethod(e);
}

private static void OnEventArgs(EventArgs e)
{
    Console.WriteLine("Simple event args: " + e);
}

private static void OnMyEventArgs(EventArgs e)
{
    var myEventArgs = (MyEventArgs)e;
    Console.WriteLine("My event args: " + myEventArgs);
}

private static void OnUnknownEventArgs(EventArgs e)
{
    Console.WriteLine(String.Format("Unknown event args ({0}): {1}", e.GetType(), e);
}

private static void Main(string[] args)
{
    MyMethod(null, new EventArgs());
    MyMethod(null, new MyEventArgs());
    MyMethod(null, new AnotherEventArgs());

    Console.ReadKey();
}
Oliver
  • 43,366
  • 8
  • 94
  • 151
1

have you thought of using method overloads instead? generally spoken i would try to avoid switch case blocks, with view exceptions, since they are often a smell that inheritance, overloads, etc. could solve the problem in a nicer way.

BR

Matthias
  • 1,267
  • 1
  • 15
  • 27
  • Sounds interesting. Could you give an example of this? – grmihel Nov 18 '14 at 16:26
  • simple method overloads for each type of EventArgs that you want to handle: `void MyMethod(object sender, MyEventArgs e) {/* do some code */} .... void MyMethod(object sender, MyOtherEventArgs e) {/* do some other code */}` that way you could avoid the swith case block because the types are separated by the method signature. of course you can always over-complicate things so you have to determine if sthg like that makes sense in your concrete code. however, i always consider switch case as a smell and take a rough look if sthg should be refactored – Matthias Nov 19 '14 at 16:29
0

Only for completeness, this will work, but you should NOT do this, for reasons that should be very obvious:

void MyMethod(object sender, EventArgs e)
{
    switch(e.GetType().FullName)
    {
        case "MyNamespace.MyEventArgs":
            //seriously, don't do this.
            break;
        case "System.EventArgs":
            //this is the worst idea ever.
            break;
        default:
            break;
    }
}
Rotem
  • 21,452
  • 6
  • 62
  • 109
  • Were thinking the same, but this would be a REALLY ugly implementation of it, but sure it would work, unless you suddenly mess up namespaces :) – grmihel Nov 18 '14 at 16:25
  • Implemenenting it this way would nominate you for a spot on http://thedailywtf.com/ – Rotem Nov 18 '14 at 16:28