Switch case on type c#

C#.NetOptimizationSwitch Statement

C# Problem Overview


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

Hello suppose i get a big if/else on class type. it's there a way to do it with a switch case ?

Example :

function test(object obj)
{
if(obj is WebControl)
{

}else if(obj is TextBox)
{

}
else if(obj is ComboBox)
{

}

etc ...

I would like to create something like

switch(obj)
{
case is TextBox:
break;
case is ComboBox:
break;

}

}

C# Solutions


Solution 1 - C#

Update C# 7

Yes: Source

switch(shape)
{
    case Circle c:
        WriteLine($"circle with radius {c.Radius}");
        break;
    case Rectangle s when (s.Length == s.Height):
        WriteLine($"{s.Length} x {s.Height} square");
        break;
    case Rectangle r:
        WriteLine($"{r.Length} x {r.Height} rectangle");
        break;
    default:
        WriteLine("<unknown shape>");
        break;
    case null:
        throw new ArgumentNullException(nameof(shape));
}

Prior to C# 7

No.

http://blogs.msdn.com/b/peterhal/archive/2005/07/05/435760.aspx

> We get a lot of requests for addditions to the C# language and today > I'm going to talk about one of the more common ones - switch on type. > Switch on type looks like a pretty useful and straightforward feature: > Add a switch-like construct which switches on the type of the > expression, rather than the value. This might look something like > this:

switch typeof(e) { 
        case int:    ... break; 
        case string: ... break; 
        case double: ... break; 
        default:     ... break; 
}

> This kind of statement would be extremely useful for adding virtual > method like dispatch over a disjoint type hierarchy, or over a type > hierarchy containing types that you don't own. Seeing an example like > this, you could easily conclude that the feature would be > straightforward and useful. It might even get you thinking "Why don't > those #*&%$ lazy C# language designers just make my life easier and > add this simple, timesaving language feature?" > > Unfortunately, like many 'simple' language features, type switch is > not as simple as it first appears. The troubles start when you look at > a more significant, and no less important, example like this:

class C {}
interface I {}
class D : C, I {}

switch typeof(e) {
case C: … break;
case I: … break;
default: … break;
}

Link: https://blogs.msdn.microsoft.com/peterhal/2005/07/05/many-questions-switch-on-type/

Solution 2 - C#

The following code works more or less as one would expect a type-switch that only looks at the actual type (e.g. what is returned by GetType()).

public static void TestTypeSwitch()
{
    var ts = new TypeSwitch()
        .Case((int x) => Console.WriteLine("int"))
        .Case((bool x) => Console.WriteLine("bool"))
        .Case((string x) => Console.WriteLine("string"));

    ts.Switch(42);     
    ts.Switch(false);  
    ts.Switch("hello"); 
}

Here is the machinery required to make it work.

public class TypeSwitch
{
    Dictionary<Type, Action<object>> matches = new Dictionary<Type, Action<object>>();
    public TypeSwitch Case<T>(Action<T> action) { matches.Add(typeof(T), (x) => action((T)x)); return this; } 
    public void Switch(object x) { matches[x.GetType()](x); }
}

Solution 3 - C#

Yes, you can switch on the name...

switch (obj.GetType().Name)
{
    case "TextBox":...
}

Solution 4 - C#

Here's an option that stays as true I could make it to the OP's requirement to be able to switch on type. If you squint hard enough it almost looks like a real switch statement.

The calling code looks like this:

var @switch = this.Switch(new []
{
	this.Case<WebControl>(x => { /* WebControl code here */ }),
	this.Case<TextBox>(x => { /* TextBox code here */ }),
	this.Case<ComboBox>(x => { /* ComboBox code here */ }),
});

@switch(obj);

The x in each lambda above is strongly-typed. No casting required.

And to make this magic work you need these two methods:

private Action<object> Switch(params Func<object, Action>[] tests)
{
	return o =>
	{
		var @case = tests
			.Select(f => f(o))
			.FirstOrDefault(a => a != null);
			
		if (@case != null)
		{
			@case();
		}
	};
}

private Func<object, Action> Case<T>(Action<T> action)
{
	return o => o is T ? (Action)(() => action((T)o)) : (Action)null;
}

Almost brings tears to your eyes, right?

Nonetheless, it works. Enjoy.

Solution 5 - C#

The simplest thing to do could be to use dynamics, i.e. you define the simple methods like in Yuval Peled answer:

void Test(WebControl c)
{
...
}

void Test(ComboBox c)
{
...
}

Then you cannot call directly Test(obj), because overload resolution is done at compile time. You have to assign your object to a dynamic and then call the Test method:

dynamic dynObj = obj;
Test(dynObj);

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionC&#233;dric BoivinView Question on Stackoverflow
Solution 1 - C#SteveView Answer on Stackoverflow
Solution 2 - C#cdigginsView Answer on Stackoverflow
Solution 3 - C#Timothy KhouriView Answer on Stackoverflow
Solution 4 - C#EnigmativityView Answer on Stackoverflow
Solution 5 - C#Francesco BaruchelliView Answer on Stackoverflow