Pattern Matching on a string - c#

I was wondering if there is a way to do something like this in c# 7
var test = "aaeag";
switch (test)
{
case test.StartsWith("a"):
break;
default:
break;
}
Sadly it does not look like it possible. Is this correct or am I doing something wrong?

This is possible with C# 7, using a when guard:
var test = "aaeag";
switch (test)
{
case var s when s.StartsWith("a"):
break;
default:
break;
}
What your version of the code is doing is often referred to as active patterns. By eg defining the the extension method:
public static bool StartsWithPattern(this string str, string matchPattern) =>
str.StartsWith(matchPattern);
Then your switch could become:
var test = "aaeag";
switch (test)
{
case StartsWith("a"):
break;
default:
break;
}
If you'd like to see this feature in a future C# version, then please upvote this proposal.

Related

C# Case which include other cases

How to execute in one case, other cases? I could just copy paste those other cases, or put it to some external function but there is so much code so I dont want to do that.
Example:
switch(foo)
{
case 3:
{
//something
}break;
case 4:
{
//something else
}break;
case 5:
{
//here i want to execute case 3 and case 4
}break;
}
I think that this was previously answered but I can't find how to do it.
C# doesn't have such functionality. You have to create other methods which will do actions for cases 3 and 4 and call them from case 5 branch. I would suggest to create a separate class FooHandler which would handle your value. It's easily extendable and readable.
public class FooHandler
{
private readonly int _foo;
public FooHandler(int foo)
{
this._foo = foo;
}
public void Handle()
{
switch(this._foo)
{
case 3: this.HandleCase3(); break;
case 4: this.HandleCase4(); break;
case 5: this.HandleCase5(); break;
default: throw new ArgumentException("Foo value is invalid");
}
}
private void HandleCase3()
{
// Your code for case 3
}
private void HandleCase4()
{
// Your code for case 4
}
private void HandleCase5()
{
this.HandleCase3();
this.HandleCase4();
}
}
Usage:
var fooHandler = new FooHandler(foo);
fooHandler.Handle();
If you don't want to add methods (you didn't explain why),
you can use Action local variables holding Lambda expressions.
In the example below you can replace the body of the lambdas with whatever code you have for "something" and "something else".
Action also supports passing arguments to the lambda's body if you need them.
Action something = () => { Console.WriteLine("something"); };
Action something_else = () => { Console.WriteLine("something_else"); };
switch (foo)
{
case 3:
something();
break;
case 4:
something_else();
break;
case 5:
something();
something_else();
break;
}
You could also change the switch to two ifs:
if (foo == 3 || foo == 5)
{
//something
}
if (foo == 4 || foo == 5)
{
//something else
}
It would be easier to use if-statements. Here I also used pattern matching to simplify the tests.
if (foo is 3 or 5) {
// something
}
if (foo is 4 or 5) {
// something else
}
So simple and easy to read and understand.
I would argue that the code being intuitive is important; hence, I would suggest defining helper variables that clarify intention.
While not knowing the meaning of 3, 4 and 5, a hypothetical example could be:
var awesomeFoos = new[] { 3, 5 };
var popularFoos = new[] { 4, 5 };
var fooIsAwesome = awesomeFoos.Contains(foo);
var fooIsPopular = popularFoos.Contains(foo);
if (fooIsAwesome)
{
// something (preferably refactored to a separate method)
}
if (fooIsPopular)
{
// something else (preferably refactored to a separate method)
}
, where .Contains() is found in the System.Linq namespace.
An example fiddle is found here.
That being said, though; you seem quite determined that you would prefer to keep your code as-is, to an as large extent as possible. If that is really a high priority, you could consider putting the whole foo-switch logic inside a method and let it call itself twice in the case 5 scenario:
private static void HandleFoo(int foo)
{
switch(foo)
{
case 3:
{
// something
}break;
case 4:
{
// something else
}break;
case 5:
{
HandleFoo(3);
HandleFoo(4);
}break;
}
}
Example fiddle is found here.
(Depending on the content of // something and // something else, this may not be feasible, though.)
I strongly recommend changing the way you want to implement this statement. This method is not suitable for modern applications and is coupled with everything. But if you need to implement as you asked, You can jump between cases by using goto.
For more information Read "jump statements".
int a = 10;
switch (a)
{
case 0:
//Condition1:
//some actions
break;
case 1:
goto case 0;
//or
goto Condition1;
break;
default:
break;
}
Since this is the linear approach you should check conditions in if for each goto in each case(cause you can't Go back to each step)
Another approach is to save all cases in the order you want to execute and run the switch multiple times. I use a while in my example you can use goto if you don't want to use a loop.
Queue<int> cases = new Queue<int>();
//1 is the main switch value
cases.Enqueue(1);
while (cases.Count > 0)
{
int temp = cases.Dequeue();
switch (temp)
{
case 0:
Console.WriteLine("0");
break;
case 1:
Console.WriteLine("1");
cases.Enqueue(3);//run case 3
cases.Enqueue(0);//then run case 0
break;
case 2:
Console.WriteLine("2");
break;
case 3:
Console.WriteLine("3");
break;
default:
break;
}
}

Can I use the recent c# addition 'case when' clause to use StartsWith in a switch?

case when is fairly new so many answers don't touch upon it. The MSDN example is about casting the object, not using the original string.
switch (catName)
{
case string c when c.StartsWith("Fluffy"):
// DoSomething
break;
}
This seems to work, it'd be nicer if you could omit the string c part and just do when catName instead. But then multiple cases don't work:
switch (catName)
{
case string c when c.StartsWith("Fluffy"):
case string c when c.StartsWith("Mr"):
// DoSomething
break;
}
Because you can't declare two string c. So you could change the second one, but you'd end up with a list of string a, string b, string c etc which doesn't seem very nice.
The ideal way would of course be something like:
switch (catName)
{
case when catName.StartsWith("Fluffy"):
...
break;
}
Is there an elegant way to solve this, or is it simply better to use an if..else if method?
No you can't, because you are using the pattern matching into the switch statement and the type is evaluated at compile time:
expr has a compile-time type that is a base class of type
Anyway, you can use the same variable names because their scope is local. Reference
Edit:
My favourite solution is suggested by kofifus in the comments:
string catName = "Fluffy";
switch (catName)
{
case {} when catName.StartsWith("Fluffy"):
case {} when catName.StartsWith("Mr"):
Console.WriteLine(catName);
break;
default:
Console.WriteLine("Name does not start with Mr or Fluffy.");
break;
}
I know you said two different strings isn't nice, but this looks very readable to me, is there really a problem with doing it like this:
string catName = "Fluffy";
switch (catName)
{
case string c when c.StartsWith("Fluffy"):
case string d when d.StartsWith("Mr"):
Console.WriteLine(catName);
break;
default:
Console.WriteLine("Name does not start with Mr or Fluffy.");
break;
}
Alternatively, based on the 'Reference' link in Krustys answer you could do it like this:
string catName = "Noodle";
switch (catName)
{
case string c when (c.StartsWith("Fluffy") || c.StartsWith("Mr")):
Console.WriteLine(catName);
break;
default:
Console.WriteLine("Name does not begin with Mr or Fluffy.");
break;
}

C# - Get switch value if in default case

Help please, I have this case:
switch(MyFoo()){
case 0: //...
break;
case 1: //...
break;
case 2: //...
break;
default:
// <HERE>
break;
}
As you can see the switch gets the value directly from a method without saving it as a variable.
Is it possible to get which value fires the default case?
For example if MyFoo() returns 7, how can I get that value?
I want to avoid to save the method result as a variable, is there a way to get the switch value from inside a case? Something like this:
default:
this.SwitchValue // <<--
break;
Thank you for reading,
~Saba
Is there a way to get the switch value from inside a case?
The only (proper) way is actually to store the result of MyFoo() in a variable.
var fooResult = MyFoo();
switch (fooResult)
{
case 0:
...
break;
...
default:
handleOthersCase(fooResult);
break;
}
This code is readable and understandable and have no extra cost (As #SheldonNeilson says: It's on the stack anyway).
Also, the MSDN first example about switch totally look like this. You can also find informations int the language specification.
You also can make your own switch based on a dictionary, but the only advantage I see is that you can use it for complex cases (any kind of object instead of string/int/...). Performance is a drawback.
It may look like this:
public class MySwitch<T> : Dictionary<T, Action<T>>
{
private Action<T> _defaultAction;
public void TryInvoke(T value)
{
Action<T> action;
if (TryGetValue(value, out action))
{
action(value);
}
else
{
var defaultAction = _defaultAction;
if (defaultAction != null)
{
defaultAction(value);
}
}
}
public void SetDefault(Action<T> defaultAction)
{
_defaultAction = defaultAction;
}
}
And be used like this:
var mySwitch = new MySwitch<int>();
mySwitch.Add(1, i => Console.WriteLine("one")); // print "one"
mySwitch.Add(2, i => Console.WriteLine("two")); // print "two"
mySwitch.SetDefault(i => Console.WriteLine("With the digits: {0}", i)); // print any other value with digits.
mySwitch.TryInvoke(42); // Output: "With the digits: 42"
Or based on this response, this:
public class MySwitch2<T>
{
private readonly T _input;
private bool _done = false;
private MySwitch2(T input)
{
_input = input;
}
public MySwitch2<T> On(T input)
{
return new MySwitch2<T>(input);
}
public MySwitch2<T> Case(T caseValue, Action<T> action)
{
if (!_done && Equals(_input, caseValue))
{
_done = true;
action(_input);
}
return this;
}
public void Default(Action<T> action)
{
if (!_done)
{
action(_input);
}
}
}
Can be used like that:
MySwitch2<int>.On(42)
.Case(1, i => Console.WriteLine("one"))
.Case(2, i => Console.WriteLine("two"))
.Default(i => Console.WriteLine("With the digits: {0}", i));
I can't see a reason as well why to use it like that but may be a work around will be like this:
int x;
switch ( x = MyFoo())
{
case 0: //...
break;
case 1: //...
break;
case 2: //...
break;
default:
var s = x; // Access and play with x here
break;
}
No, this isn't possible.
You can assign the value to variable inside switch, if you want to look like reinventing the wheel:
int b;
.....
switch (b = MyFoo())
{
case 1:
break;
case 2:
break;
default:
//do smth with b
break;
}
The easiest way is to save the result of MyFoo() as a variable.. But if you don't want to do that you could do:
switch(MyFoo()){
case 0: //...
break;
case 1: //...
break;
case 2: //...
break;
default:
this.SwitchCase = MyFoo();
break;
}
Although I would advise against this and say save the value as a variable to save your program the extra work.
Saving the value of MyFoo as a variable becomes more important the more complex the example gets as the value of MyFoo could have changed between the switch and default case.
Also this will only work where MyFoo has no side-effects and obviously must always return the same value for any given parameter.
for example the following would work:
Private int MyFoo()
{
return 3;
}
But the following would not:
private int MyFoo()
{
Random r = new Random();
return r.Next(5);
}
This is possible now.
https://learn.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-8#property-patterns
Example:
int? TryGetColumnIndex(string columnName)
=> GetValue(columnName)
switch
{ var result when result > -1 => result, _ => new int?() };
result will capture the result of GetValue.
Even cooler, you can do propery checks.
i.e instead of when result > -1 you can even say when result.ToString().Length > 2 and such.

Why doesn't this goto inside this switch work?

For this program:
class Program
{
static void Main(string[] args)
{
var state = States.One;
switch (state)
{
case States.One:
Console.WriteLine("One");
break;
case States.Zero:
goto case States.One;
}
}
}
public enum States : ulong
{
Zero = 0,
One = 1,
}
I got:
"A switch expression or case label must be a bool, char, string,
integral, enum, or corresponding nullable type"
But state variable is enum type. The error disappears if I comment the goto case line.
I am using VS 2013. + .NET 4.5.1.
This is known bug of the C# compiler when enum is typed as ulong and you use goto case at the same time. If you remove the ulong from enum, it compiles just fine. And because not many people run into this problem, they are not focusing on fixing it.
Depending on your use case, this might also be an option for you:
switch (state)
{
case States.Zero:
case States.One:
Console.WriteLine("One");
break;
}
This should be working according to an example here: http://msdn.microsoft.com/de-de/library/06tc147t.aspx
You could use a label for goto instead of using the case directly in the goto statement:
switch (state)
{
case States.One:
caseZeroRedirect:
Console.WriteLine("One");
break;
case States.Zero:
CouldDoSomethingFirst();
goto caseZeroRedirect;
}
You should try this:-
switch (state)
{
case States.Zero:
case States.One:
Console.WriteLine("1");
break;
}

Can switch case being used like a void method?

Usually I will implement switch case in a method that return particular object. Something like below:
private string testing(string input){
switch(input)
{
case "a":
{
....
return "TestingResult";
}
case "b":
{
....
return "TestingResultB";
}
default:
return null;
}
}
Now I'm wondering if it's possible to write a switch case for value assignment purpose? Something like below:
private string testing(string input){
string TEST="";
switch(input)
{
case "a":
{
....
TEST = "TestingResult";
}
case "b":
{
....
TEST = "TestingResultB";
}
default:
}
return TEST;
}
Of cause it can be achieve by simple If-Else statement, this question is for me to understand more functionality of switch case
Of course, after testing it, I receive error
control cannot fall through from one case label('case: "a"') to another
You need to add break; in each case
private string testing(string input){
string TEST="";
switch(input)
{
case "a":
TEST = "TestingResult";
break;
case "b":
TEST = "TestingResultB";
break;
default:
}
return TEST;
}
As others have mentioned, the braces within each case are unnecessary.
Yes you can. You just have to remember to put a 'jump' statement of some kind (this includes break, goto case, return, or throw), after each case label:
private string testing(string input){
string TEST="";
switch(input)
{
case "a":
TEST = "TestingResult";
break;
case "b":
TEST = "TestingResultB";
break;
}
return TEST;
}
Note, the braces here are unnecessary, and the default isn't required in this construction as it will fall through the switch block if it doesn't match any of the cases.
Further Reading
switch (C# Reference)
What you've written is perfectly legitimate, however there is no point doing the value assignment unless you are going to carry on and do some further operations with it before returning.
To help you with becoming more proficient with switch/case statements:
in your first example you don't need the default, just have a final return at the end of the function
in your second example, you don't need the default at all - you do nothing with it
a switch/case is usually used for multiple options, for example 4 or more. Any less than that and an if/else is equally readable. You should also bear in mind that a switch/case can give you good speed improvements in some cases

Categories

Resources