0

Is it possible to use the switch when comparing Classes in a generic method? Example:

switch (typeof(T))
{
    case typeof(Class1):
        // ...
        break;

    case typeof(Class2):
        // ...
        break;

    default:
        break;
}

The idea is not to use the name but the Class object. At moment I'm using:

if (typeof(T) == typeof(Class1))
{
   // ...
}
else if (typeof(T) == typeof(Class2))
{
   // ...
}

For simplicity, it would be good to use the switch.

ptuga
  • 69
  • 1
  • 11
  • 3
    The C# v7.1 patterned switch won't help you: `An expression of type 'T' cannot be handled by a pattern of type 'Class1'`. I think your `if / else if` pattern is as good as you are going to get – Flydog57 Feb 04 '19 at 23:53
  • `create a string which depends on the Class properties, which again can vary from Class1 to Class2.` What do those strings look like? You should consider adding that logic to the classes (`Class1` etc) themselves - rather than to this method. Then this method can call the method you add to `Class1` / `Class2` etc (even better if you have an interface that defines the method, that each class implements). – mjwills Feb 05 '19 at 00:00
  • 2
    @ptuga Are you conflating the C# version with the .NET version? – Jonathon Chase Feb 05 '19 at 00:08
  • The original duplicate works fine with .NET 4.5 @ptuga - https://stackoverflow.com/a/42488315/34092 - pattern matching is just syntactic sugar. What IDE are you using? – mjwills Feb 05 '19 at 00:11
  • @Jonathon Chase: Target Framework .NET Framework 4.5 – ptuga Feb 05 '19 at 00:12
  • 1
    @ptuga You should be fine using C# 7 then, assuming Visual Studio 2017+. The language version won't impact your framework target. – Jonathon Chase Feb 05 '19 at 00:14
  • Possible duplicate of https://stackoverflow.com/a/43080709/34092 . – mjwills Feb 05 '19 at 00:16
  • @Jonathon Chase: In my case, the Language version needs to be C# 5 because of the compiler. All the examples use C# 7 which I cannot use. Any more thoughts? – ptuga Feb 06 '19 at 00:29

3 Answers3

2

In cases like this, I use dictionaries, paired with values of lambdas as fit for the specific problem at hand.

var options = new Dictionary<Type, Action>()
{
    { typeof(string), () => doSomething() },
    { typeof(int), () => doSomething() },
    ...
};

Action act = null;
if (options.TryGetValue(typeof(T), out act) {
    act();
} else {
   // default
}

The dictionary is usually a static readonly field or property, so the indexing is done just once.

In your specific case you can get along with a Dictionary<Type, Func<object, string>>, like so:

private static readonly Formatters = new Dictionary<Type, Func<object, string>>()
{
    { typeof(Class1), o => ((Class1)o).format() },
    { typeof(Class2), o => FormatClass.FormatClass2((Class2)o) },
    ...
};

T instance;
string formatted = Formatters[typeof(T)](instance);
Alberto Chiesa
  • 7,022
  • 2
  • 26
  • 53
  • This options are not simpler than a `If/else if`solution. – ptuga Feb 05 '19 at 00:15
  • 2
    It depends upon what you _think_ is simple. I find it a lot more compact (usually 1 row/class instead of 4) and quite easy to check. 10 classes are easily checked in a dictionary, not so easily checked in code. And last but not least, having a dictionary allows you to make the whole thing configurable. Frankly, I care more about ease of maintenance and readability, and less about simplicity. YMMV, – Alberto Chiesa Feb 05 '19 at 00:21
  • @ptuga yes. The solution I provided allows you to do that. You need to cast the object to the specific type. But you need that anyway. Once you cast to the specific type, you can access the properties of that specific class. If you don’t want to cast, you don’t want a switch: you want typed implementations of a generic abstract class. – Alberto Chiesa Feb 06 '19 at 00:39
  • The idea would be to perform my code as in a switch. The doSomething() means something outside my method and does not differentiate between the different T. Because I need to work with the props of the class e.g. for Class1 could be string s = prop1 + "\t" + prop2 on Class2 could be different string s = prop2 + "\t" + prop3 (it can even be a List). Not sure if this can help me. I don't have enough knowledge to understand it. – ptuga Feb 06 '19 at 00:41
  • @ptuga then I suggest you to try it until you understand it. if something specific is not understood, let me know. – Alberto Chiesa Feb 06 '19 at 00:45
1

Expanding on Anu Viswan's answer, Since C# 7.1, this is valid:

public void Method<T>(T param)
{
    switch (param)
    {
        case A a:
            Console.WriteLine("A");
            break;
        case B b:
            Console.WriteLine("B");
            break;
    }
}
Paulo Morgado
  • 14,111
  • 3
  • 31
  • 59
0

If you are using C# 7, you can make use of pattern matching.

For example,

public void Method<T>(T param)
{
    switch(param)
    {
        case var _ when param is A:
        Console.WriteLine("A");
        break;
        case var _ when param is B:
        Console.WriteLine("B");
        break;

    }
}

Where

public class A{}
public class B{}
Anu Viswan
  • 17,797
  • 2
  • 22
  • 51