How to use switch-case on a Type? [duplicate]
Asked Answered
H

4

24

Possible Duplicate:
Is there a better alternative than this to 'switch on type'?

I need to iterate through all properties of my class and to check if its type of int the i need to do something, if its string .. then do something. I need it using switch-case. Here i am using switch in the following manner, but it asks for some constant. see the code below:

 public static bool ValidateProperties(object o)
{
    if(o !=null)
    {
        var sourceType = o.GetType();
        var properties = sourceType.GetProperties(BindingFlags.Public | BindingFlags.Static);
        foreach (var property in properties)
        {
            var type = property.GetType();
            switch (type)
            {
                *case typeof(int):* getting error here
                    // d
            }
        }
    }
}

Also i want to know , what check should I use, typeof(int) or typeof(Int32)?

Huss answered 25/9, 2011 at 0:16 Comment(3)
FYI, both questions are of different context. He is asking on controls , while i am asking on data types. Please be sure before any down voting or close voting. Don't be blind. Guys having such reputations are not supposed to do such kiddish mistakes.Huss
see also https://mcmap.net/q/35757/-is-there-any-benefit-to-this-switch-pattern-matching-idea https://mcmap.net/q/35758/-switch-case-on-type-c-duplicate https://mcmap.net/q/35760/-c-switch-on-type-duplicate #299476Flapjack
and #94805 #7150288 #6305315 #5947843 #10115528 #2552273Flapjack
T
55

You cannot use a switch block to test values of type Type. Compiling your code should give you an error saying something like:

A switch expression or case label must be a bool, char, string, integral, enum, or corresponding nullable type

You'll need to use if-else statements instead.

Also: typeof(int) and typeof(Int32) are equivalent. int is a keyword and Int32 is the type name.

UPDATE

If you expect that most types will be intrinsic you may improve performance by using a switch block with Type.GetTypeCode(...).

For example:

switch (Type.GetTypeCode(type))
{
    case TypeCode.Int32:
        // It's an int
        break;

    case TypeCode.String:
        // It's a string
        break;

    // Other type code cases here...

    default:
        // Fallback to using if-else statements...
        if (type == typeof(MyCoolType))
        {
            // ...
        }
        else if (type == typeof(MyOtherType))
        {
            // ...
        } // etc...
}
Thatcher answered 25/9, 2011 at 0:21 Comment(0)
F
11

A good and extensible way to do this is to make a dictionary of types and delegates of appropriate type, based on what you want to do with values of that type.

For example:

var typeProcessorMap = new Dictionary<Type, Delegate>
{
    { typeof(int), new Action<int>(i => { /* do something with i */ }) },
    { typeof(string), new Action<string>(s => { /* do something with s */ }) },
};

And then:

void ValidateProperties(object o)
{
    var t = o.GetType();
    typeProcessorMap[t].DynamicInvoke(o); // invoke appropriate delegate
}

This solution is extensible, configurable even at run time, and as long as you keep the keys and types of delegate values in typeProcessorMap correctly matched is also type safe.

See it in action.

Ferreira answered 25/9, 2011 at 0:36 Comment(4)
This is a nice solution, bearing in mind that DynamicInvoke can be a bit slow in performance-critical sections.Lipoprotein
@KirkWoll: Would making all of the delegates Action<object> and casting the parameter inside the delegate body be faster? I 'm not sure exactly what DynamicInvoke does behind the scenes.Ferreira
I'm not sure exactly what DynamicInvoke does behind the scenes either. :) But I posted an "answer" below to illustrate the performance difference.Lipoprotein
Apparently has/had Skeet's blessing in 2008. Fwiw, however, the ideone link isn't working for me (OS X & Safari).Auroraauroral
L
5

This "answer" is an elaboration for Jon's answer. (Marking CW)

For the record, DynamicInvoke is a bit slow. To illustrate this, consider the following program:

void Main()
{
    Func<int, string> myFunc = i => i.ToString();
    myFunc.DynamicInvoke(1);   // Invoke once so initial run costs are not considered
    myFunc(1);

    Stopwatch stopwatch = new Stopwatch();

    stopwatch.Start();
    for (int i = 0; i < 1000000; i++)
        myFunc.DynamicInvoke(1);
    stopwatch.Stop();

    var elapsed = stopwatch.Elapsed;

    stopwatch.Restart();
    for (int i = 0; i < 1000000; i++)
        myFunc(1);
    stopwatch.Stop();

    var elapsed2 = stopwatch.Elapsed;

    Console.WriteLine("DynamicInvoke: " + elapsed);
    Console.WriteLine("Direct Invocation: " + elapsed2);
}

Prints out:

DynamicInvoke: 00:00:03.1959900
Direct Invocation: 00:00:00.0735220

Which means that DynamicInvoke (in this simple case) is 42 times slower than direct invocation.

Lipoprotein answered 25/9, 2011 at 0:16 Comment(0)
A
5

Usually, the easiest solution is to switch on the type name:

switch (type.Name)
{
    case "Int32":
    ...
}
Annitaanniversary answered 25/9, 2011 at 0:22 Comment(3)
IMO, the sacrifice of type-safety is not worth it. After all, an if/else chain is almost equally concise and has the virtue of catching typos (and far more importantly -- future refactorings) at compile-time.Lipoprotein
Have you guys heard about unit tests? Anyway, I do use Jon's approach sometimes, but it's usually overkill.Annitaanniversary
@Diego, unit tests are not a replacement for type safety.Lipoprotein

© 2022 - 2024 — McMap. All rights reserved.