Can I write switch case in c# like this?
switch (string)
case [a..z]+
// do something
case [A..Z]+
// do something
....
Yes you can in C# 7 (and nobody noticed I had used the incorrect range character in the character class .. instead of -). Updated now with a slightly more useful example that actually works:
using System.Text.RegularExpressions;
string[] strings = {"ABCDEFGabcdefg", "abcdefg", "ABCDEFG"};
Array.ForEach(strings, s => {
switch (s)
{
case var someVal when new Regex(#"^[a-z]+$").IsMatch(someVal):
Console.WriteLine($"{someVal}: all lower");
break;
case var someVal when new Regex(#"^[A-Z]+$").IsMatch(someVal):
Console.WriteLine($"{someVal}: all upper");
break;
default:
Console.WriteLine($"{s}: not all upper or lower");
break;
}
});
Output:
ABCDEFGabcdefg: not all upper or lower
abcdefg: all lower
ABCDEFG: all upper
A minor refinement on David's excellent answer using _ as a discard.
Just a very simple string value as an example.
using System;
using System.Text.RegularExpressions;
public class Program
{
public static void Main()
{
string userName = "Fred";
int something = 0;
switch (true)
{
case bool _ when Regex.IsMatch(userName, #"Joe"):
something = 1;
break;
case bool _ when Regex.IsMatch(userName, #"Fred"):
something = 2;
break;
default:
break;
}
Console.WriteLine(something.ToString());
}
}
Starting with C# 8.0, the answer is now YES!... sort of.
With 8.0, the switch expression was introduced. You can use that to match many different styles of patterns as show below.
string myValueBeingTested = "asdf";
string theResultValue = myValueBeingTested switch
{
var x when
Regex.IsMatch(x, "[a..z]+") => "everything is lowercase",
var y when
Regex.IsMatch(y, "[A..Z]+") => "EVERYTHING IS UPPERCASE",
"Something Specific" => "The Specific One",
_ => "The default, no match scenario"
};
How it works: The switch expression needs a variable that it can feed the results into. The above sample uses theResultValue variable for that. Next you pass into the switch what is referred to as the range expression represented by myValueBeingTested above. The familiar case construct is replaced with a pattern expression followed by the => token and together referred to as an expressionn arm. Anything on the right side of the arm token will end up in the result variable.
Normally the switch expression requires that patterns be a compile-time constant, and you cannot execute arbitrary code inside a switch expression. However we can use a case gaurd pattern by using the when clause to make use of Regex as shown above. Each case needs to be wired up in a distinct arm with distinct throw-away variables, (x and y above).
The 3rd arm shown above is a compile-time constant string to match some specific text if desired. The 4th arm shown above uses the _ pattern, which is a sort of wildcard similar to the old default: keyword. You can also use null instead of, or in addition to _ to handle null cases separately from anything else.
Try it out in my .NET Fiddle sample here.
You should be able to do something like this:
using System.Text.RegularExpressions;
private void fauxSwitch(string caseSwitch)
{
if(Regex.Match(caseSwitch, #"[a..z]+").Success)
{
//do something
return;
}
if(Regex.Match(caseSwitch, #"[A..Z]+").Success)
{
//do something
return;
}
/*default*/
//do something
}
Although, Pattern matching in C#7 is probably the better option.
No. In C# (prior to 7) the switch statement only accepts constant values.
Using more complex expressions as you've suggested is a feature known as 'pattern matching' in the functional programming world.
Pattern matching is included in C#7
Related
I am working on .NET 6.0 application, I have enum that I am trying to use in switch as to compare with string value but getting exception.
error
private static bool ValidateAlphanumericCase(string text, string fieldName)
{
if (!string.IsNullOrWhiteSpace(fieldName))
{
var rule = GetRule(fieldName).TxtFieldFormat; // string value
switch (rule)
{
case TextFieldFormat.AlphanumericUpperCase.ToString():
break;
case TextFieldFormat.AlphanumericLowerCase.ToString():
break;
}
}
else
{
new EmptyFieldNameException();
}
return false;
}
enum
public enum TextFieldFormat
{
AlphanumericUpperCase = 0,
AlphanumericLowerCase = 1,
}
TextFieldFormat.AlphanumericUpperCase.ToString()
This is a method invocation expression and it is not a valid pattern for swith statement.
You can find all valid patterns here: https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/operators/patterns
The closest pattern is type pattern or constant pattern, I guess the compiler recognizes AlphanumericUpperCase as a nested class of TextFieldFormat and fails.
In this case you can use nameof operator.
switch (rule)
{
case nameof(TextFieldFormat.AlphanumericUpperCase):
break;
case nameof(TextFieldFormat.AlphanumericLowerCase):
break;
}
Seems you understood switch-case block a little bit different.
A switch block is simply a shortcut (but more performant shortcut) of many if - else if - else blocks.
Of course they are not the same, but their working logic almost the same.
With this very little info, you can easily think about what's wrong in your code.
Bingo, you're right! Case blocks should check the state. (Boolean value..Just interests with either the given statement results true or false..)
After checking the boolean result, Which case's statement match, code continues on that case block.
So, in your situation your code could be like this :
switch (rule)
{
/// Some statements need to put in paranthesis. Also you would need put business codes of cases into curly braces.
/// I write from my mind.
/// So please try paranthesis and/or braces if this code break.
case rule==TextFieldFormat.AlphanumericUpperCase.ToString():
DoSomethingWithFirstCase(); break;
case rule==TextFieldFormat.AlphanumericLowerCase.ToString():
DoSomethingWitSecondCase(); break;
default: DoSomethingWhenNoMatchWithOtherCases();
}
Hope this helps.
You can also use it this way
TextFieldFormat.AlphanumericUpperCase.ToString("g" or "G")
This question already has an answer here:
Switch with ToLower() causes error CS0426 The type name '' does not exist in the type ''
(1 answer)
Closed 1 year ago.
Can someone explain this error to me, I just don't get how it thinks there's a type involved
var header = "ABCDEfooGHIJ";
switch (true)
{
case header.Contains("foo"): //error here
return true;
case header.Contains("bar"): //and here
return false;
}
Error = 'header' is a variable but is used like a type
switch (true) isn't a "thing" in C# like it's VB counterpart (Select True) . And even if it was, I'd strongly recommend avoiding it.
When you write a switch statement in C#, the cases must either be a constant or a pattern match. If you are insistent on using a switch, you can use the following (which only works on C# 7+)
switch (header)
{
case var _ when header.Contains("foo"):
return true:
case var _ when header.Contains("bar"):
return false:
default:
throw new Exception();
}
In this case, var _ is the object pattern (which will match anything non-null) along with a discard since we want to operate on the other variable. Don't like the discard? You could do this as well:
switch (header)
{
case var h1 when h1.Contains("foo"):
return true:
case var h2 when h2.Contains("bar"):
return false:
default:
throw new Exception();
}
That said, don't use a switch for this. A chain of if/else is much more clear. Anyone reading your code (including your future self) will thank you for it.
if (header.Contains("foo"))
return true;
if (header.Contains("bar"))
return false;
// etc
I don't understand the use case of var patterns in C#7. MSDN:
A pattern match with the var pattern always succeeds. Its syntax is
expr is var varname
where the value of expr is always assigned to a local variable named
varname. varname is a static variable of the same type as expr.
The example on MSDN is pretty useless in my opinion, especially because the if is redundant:
object[] items = { new Book("The Tempest"), new Person("John") };
foreach (var item in items) {
if (item is var obj)
Console.WriteLine($"Type: {obj.GetType().Name}, Value: {obj}");
}
Here i don't see any benefits, you could have the same if you access the loop variable item directly which is also of type Object. The if is confusing as well because it's never false.
I could use var otherItem = item or use item diectly.
Can someone explain the use case better?
The var pattern was very frequently discussed in the C# language repository given that it’s not perfectly clear what its use case is and given the fact that is var x does not perform a null check while is T x does, making it appear rather useless.
However, it is actually not meant to be used as obj is var x. It is meant to be used when the left hand side is not a variable on its own.
Here are some examples from the specification. They all use features that are not in C# yet but this just shows that the introduction of the var pattern was primarly made in preparation for those things, so they won’t have to touch it again later.
The following example declares a function Deriv to construct the derivative of a function using structural pattern matching on an expression tree:
Expr Deriv(Expr e)
{
switch (e) {
// …
case Const(_): return Const(0);
case Add(var Left, var Right):
return Add(Deriv(Left), Deriv(Right));
// …
}
Here, the var pattern can be used inside the structures to “pull out” elements from the structure. Similarly, the following example simplifies an expression:
Expr Simplify(Expr e)
{
switch (e) {
case Mult(Const(0), _): return Const(0);
// …
case Add(Const(0), var x): return Simplify(x);
}
}
As gafter writes here, the idea is also to have property pattern matching, allowing the following:
if (o is Point {X is 3, Y is var y})
{ … }
Without checking the design notes on Github I'd guess this was added more for consistency with switch and as a stepping stone for more advanced pattern matching cases,
From the original What’s New in C# 7.0 post :
Var patterns of the form var x (where x is an identifier), which always match, and simply put the value of the input into a fresh variable x with the same type as the input.
And the recent dissection post by Sergey Teplyakov :
if you know what exactly is going on you may find this pattern useful. It can be used for introducing a temporary variable inside the expression:
This pattern essentially creates a temporary variable using the actual type of the object.
public void VarPattern(IEnumerable<string> s)
{
if (s.FirstOrDefault(o => o != null) is var v
&& int.TryParse(v, out var n))
{
Console.WriteLine(n);
}
}
The warning righ before that snippet is also significant:
It is not clear why the behavior is different in the Release mode only. But I think all the issues falls into the same bucket: the initial implementation of the feature is suboptimal. But based on this comment by Neal Gafter, this is going to change: "The pattern-matching lowering code is being rewritten from scratch (to support recursive patterns, too). I expect most of the improvements you seek here will come for "free" in the new code. But it will be some time before that rewrite is ready for prime time.".
According to Christian Nagel :
The advantage is that the variable declared with the var keyword is of the real type of the object,
Only thing I can think of offhand is if you find that you've written two identical blocks of code (in say a single switch), one for expr is object a and the other for expr is null.
You can combine the blocks by switching to expr is var a.
It may also be useful in code generation scenarios where, for whatever reason, you've already written yourself into a corner and always expect to generate a pattern match but now want to issue a "match all" pattern.
In most cases it is true, the var pattern benefit is not clear, and can even be a bad idea. However as a way of capturing anonymous types in temp variable it works great.
Hopefully this example can illustrate this:
Note below, adding a null case avoids var to ever be null, and no null check is required.
var sample = new(int id, string name, int age)[] {
(1, "jonas", 50),
(2, "frank", 48) };
var f48 = from s in sample
where s.age == 48
select new { Name = s.name, Age = s.age };
switch(f48.FirstOrDefault())
{
case var choosen when choosen.Name == "frank":
WriteLine(choosen.Age);
break;
case null:
WriteLine("not found");
break;
}
I'm making a project and I have a question. I have 3 enum states like this:
enum GameLevel
{
Level1,
Level2,
None,
}
There's a part in my code where I want to check if there's any level selected or none, so I wanted to do something like:
case !GameLevel.None
or
case GameLevel.Level1 || GameLevel.Level2
Is This Possible?
Various options:
Use switch with a default:
switch (level)
{
case GameLevel.None:
// Whatever
break;
default:
// Do something else
// break
}
Use switch with explicit cases:
// Note: if you add a Level3, you'd need to change this...
switch (level)
{
case GameLevel.Level1:
case GameLevel.Level2:
// Whatever
break;
}
Use an if statment:
if (level != GameLevel.None)
{
...
}
Switch is not used to get a "its not the case"-case. However you can use the default: case, which always executes, when the other cases are "false".
For your !GameLevel.None better use an if case. if(selectedGameLevel != GameLevel.None) { }
I believe the choice of assignment should be based on how many levels you plan on implementing. For less levels (as shown in your example), I would use if and else if as opposed to using switch. Switch only works better if there are more options, as it is then performed differently for faster execution. Jon Skeet's answer will guide you on how to implement the choice you make.
I have a switch case statements in c#, here all the cases i made as private constants ,is there any bad programming practice going on here, or do i need to use enumeration here and enumerator in case block.Only three constants i showed here, i have ten constants and ten case block
private const String FEASIBLESIZE = "Total FEASIBLESIZE";
private const String AVAILABLESIZE = "Total AVAILABLESIZE";
private const String EXCESSSIZE = "Total EXCESSSIZE";
.
.
switch (value.ToString())
{
case FEASIBLESIZE:
Level.Add(TEAMSIZE, test.ToString());
break;
case AVAILABLESIZE:
Level.Add(BROADSIZE, test.ToString());
break;
case EXCESSSIZE:
Level.Add(NARROWSIZE, test.ToString());
break;
.
.
.
Aside from the horrible formatting it looks roughly okay. Of course that's a bit hard to tell without actually knowing your code. Darin is correct though, in that you're not adhering to the default naming conventions (all caps is a no-go anywhere in C#).
But I have seen much worse, if that's any consolation.
What you are doing looks like something that can be replaced using a Dictionary<string,string> mapping from one size type to another.
var sizeMap = new Dictionary<string,string>();
sizeMap.Add(FEASIBLESIZE, TEAMSIZE);
sizeMap.Add(AVAILABLESIZE, BROADSIZE);
sizeMap.Add(EXCESSSIZE, NARROWSIZE);
And instead of the switch:
Level.Add(sizeMap[value.ToString()], test.ToString());
Please try to scope the case with curly braces this is just individual style but helps when lines of code grows up and also always use the default: too
case FEASIBLESIZE:
{
Level.Add(TEAMSIZE, test.ToString());
break;
}
default:
///...
break;
Your constants appear to be a candidate for Enum, I would go for Enum rather than const here....
Bad Programming Practice:
private const String FEASIBLESIZE = "Total FEASIBLESIZE";
Good Programming Practice:
private const String FEASIBLE_SIZE = "Total FEASIBLESIZE";
Better Programming Practice:
private const String FeasibleSize = "Total FEASIBLESIZE";