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
Passing Data Between Different Controller Action Methods
Order of Event Handler Execution
Implicit Typing; Why Just Local Variables
Bulk-Deleting in Linq to Entities
Usercontrol' Constructor with Parameters in C#
Naming Convention - Underscore in C++ and C# Variables
C# Dictionary - One Key, Many Values
How to Run a C# Console Application with the Console Hidden
Merging Multiple PDFs Using Itextsharp in C#.Net
Open Image from File, Then Release Lock
Creating a Comma Separated List from Ilist<String> or Ienumerable<String>
Why Doesn't C# Support the Return of References
Regular Expression to Split on Spaces Unless in Quotes
Using Multiple Versions of the Same Dll
Kill Some Processes by .Exe File Name
C# Export Private/Public Rsa Key from Rsacryptoserviceprovider to Pem String