Is There Any Benefit to This Switch/Pattern Matching Idea

Is there any benefit to this switch / pattern matching idea?

In C# 7, you can do:

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));
}

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

Switching on types is definitely lacking in C# (UPDATE: in C#7 / VS 2017 switching on types is supported - see Zachary Yates's answer). In order to do this without a large if/else if/else statement, you'll need to work with a different structure. I wrote a blog post awhile back detailing how to build a TypeSwitch structure.

https://learn.microsoft.com/archive/blogs/jaredpar/switching-on-types

Short version: TypeSwitch is designed to prevent redundant casting and give a syntax that is similar to a normal switch/case statement. For example, here is TypeSwitch in action on a standard Windows form event

TypeSwitch.Do(
sender,
TypeSwitch.Case<Button>(() => textBox1.Text = "Hit a Button"),
TypeSwitch.Case<CheckBox>(x => textBox1.Text = "Checkbox is " + x.Checked),
TypeSwitch.Default(() => textBox1.Text = "Not sure what is hovered over"));

The code for TypeSwitch is actually pretty small and can easily be put into your project.

static class TypeSwitch {
public class CaseInfo {
public bool IsDefault { get; set; }
public Type Target { get; set; }
public Action<object> Action { get; set; }
}

public static void Do(object source, params CaseInfo[] cases) {
var type = source.GetType();
foreach (var entry in cases) {
if (entry.IsDefault || entry.Target.IsAssignableFrom(type)) {
entry.Action(source);
break;
}
}
}

public static CaseInfo Case<T>(Action action) {
return new CaseInfo() {
Action = x => action(),
Target = typeof(T)
};
}

public static CaseInfo Case<T>(Action<T> action) {
return new CaseInfo() {
Action = (x) => action((T)x),
Target = typeof(T)
};
}

public static CaseInfo Default(Action action) {
return new CaseInfo() {
Action = x => action(),
IsDefault = true
};
}
}

Is there any performance gain from using a switch statement over a bunch of if()else if() in javascript?

In general, switch is faster than if - else if statements.

However, kind of best practice is to use if - else if if you got max 3 conditionals. If you're going beyond that, you should use switch statements.

The problem with if else is that it possibly needs to check multiple times before it finally reaches the code to execute. Therefore you also need to optimize the order for your conditional statements.

if( foo ) {
}
else if( bar ) {
}
else if( baz ) {
}

That code would not make much sense from a performance prospective if you expect baz to be true and foo/bar to be false most of the times.

Why is this switch on type case considered confusing?

It seems you don't expect the switch to match on subclasses. But this would break the Liskov Substitution Principle. (where if you passed in a C object, the code would work, but not with a D, even though D is a subclass of C).

Can I simplify this C# 7 switch statement to not re-state the type?

No, you can't omit the type (or var keyword masking the type), as it is a part of pattern matching here.

Consider class hierarchy (this will not compile in C#7, but will compile in further versions after full implementation)

class Geometry();
class Triangle(int Width, int Height, int Base) : Geometry;
class Rectangle(int Width, int Height) : Geometry;
class Square(int width) : Geometry;

Now we get a variable like this:

Geometry g = new Square(5);

Now we do the switch over it:

using static System.Console;

switch (g)
{
// check that g is a Triangle and deconstruct it into local variables
case Triangle(int Width, int Height, int Base):
WriteLine($"{Width} {Height} {Base}");
break;

// same for Rectangle
case Rectangle(int Width, int Height):
WriteLine($"{Width} {Height}");
break;

// same for Square
case Square(int Width):
WriteLine($"{Width}");
break;

// no luck
default:
WriteLine("<other>");
break;
}

Back to your case, consider the code:

switch (s)
{
case string x when x.Length == 3 && int.TryParse(x, out int i):
Console.WriteLine($"s is a string that parses to {i}");
break;
// will not compile with error
// An expression of type string cannot be handled by a pattern of type int.
case int x:
break;

// will win pattern matching and print the line
// {s} is an object
case object x:
Console.WriteLine($"{s} is an object");

default:
Console.WriteLine("No Match.");
break;
}

So type checking is a part of pattern matching and you can't omit it (and for C#7 it's only available to switch on types, full support is planned for C#8). Example was brought from here. The previous step was the when clause for exception handling in C#6

C# switch expression / pattern matching - when clause inside or

You could use

var result = ch switch
{
_ when ch == 'a' || str.Contains("action a") => ...

Note : I personally dislike this type switch expression, it's kind of meh and ugly looking

Or the other option is just do it the old fashioned way and create a method ¯\_(ツ)_/¯

public Bob DoSomething(char ch)
{
if(ch =='a' || str.Contains("action a"))
return DoA("some", "parameters");
...


Related Topics



Leave a reply



Submit