"a constant value is expected" error in switch statement in c# - c#

switch (Rotation.ToString())
{
case (-Math.PI / 2).ToString():
// some code
break;
}
The compiler complains about (-Math.PI / 2).ToString(), "a constant value is expected"
Isn't that a constant?

No method call is a constant value.
Incidentally, since Math.PI is a double, you might want to not use it in "equality" comparisons as you are doing here; there are well-documented pitfalls.
A better approach for a single test would be:
var target = -Math.PI / 2;
if (Math.Abs(Rotation - target) < 0.0001) {
// some code
}
If there are lots of branches, without going into delegate territory, you can do something like this:
var specialCases = new[] { -Math.PI, -Math.PI / 2 };
var epsilon = 0.001d;
var index = specialCases.Select((d, i) => Math.Abs(Rotation - d) < epsilon ? i : -1)
.Where(i => i != -1).DefaultIfEmpty(-1).First();
switch (index) {
case 0: // -Math.PI
break;
case 1: // -Math.PI / 2
break;
default: // No match
break;
}
Not the best use of LINQ, but it will allow you to get back to switch territory with a minimum of tinkering.

Jon answers the gist of the question: the result of a method call is never considered to be a constant from the compiler's perspective. You can do this:
string i = (-Math.PI / 2).ToString();
switch(i)
{
case "-1.5707963267949": Console.WriteLine("hi");
break;
}
However, bear in mind that double.ToString() may produce different results depending on the current culture info. (Hence the reason it cannot be constant.) So you're probably better off using the double value directly and, depending on the size of your switch statement, either creating a few if/else statements, or creating a Dictionary keyed on the constant value you're trying to match.
And of course, Jon's initial warning still holds true: while doing floating-point logic, you could very easily end up with a value that should be -pi/2, but which isn't exactly -pi/2, in which case your check will fail. Here be dragons.

Perhaps try:
const var SomeVar = (-Math.PI / 2).ToString();
switch (Rotation.ToString())
{
case SomeVar:
// some code
break;
}

Related

any way to use variables in c# switch case?

I know that case cannot work with non-constant values, but what should I do if its impossible to make a constant? thats my case: we have three variables, need to find that, one that will correspond to the value of the switch condition, but how to do this if the case is not able to work with non-constants? are there any workarounds?
float value = 4;
float number1 = 3, number2 = 6, number3 = 4;
switch (value)
{
case number1:
{
break;
}
case number2:
{
break;
}
case number3:
{
break;
}
}
here is the oversimplified example, and yes, you can easily do this using if/else if, but what if the number of values will be 100? what to do in that case?
One approach is to use an inverted Dictionary, where the key is the value and the value the key. Something like this:
var d = new Dictionary<int, int>();
d.Add(3, 1);
d.Add(6, 2);
d.Add(4, 3);
int keyPtr = d[value];
switch (keyPtr):
{
case 1:
//do something.
break;
case 2:
//do something else.
break;
case 3:
//do something different.
break;
}
Obviously this is simplified, and I have used int not float, but the same applies to any type. Using this technique,
your n variables, become the first n items in the Dictionary. In practice at the very least, you should check if your given value exists as a key in the Dictionary. It should help you in the right direction.
If you simply want to check whether your value variable equals to at least one of the variables number1, number2, number3, you could create an array of those numbers, say numbers[] and then create a method such as:
private bool checkValue(float value, float[] numbers) {
foreach (float num in numbers) {
if (num == value) return true;
}
return false;
}
This solution fits any number of elements in your numbers array.
If you want you can also use a List<float> instead of an array, so you could dynamically add more and more elements (Without a fixed size).

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

I'm looking at C# 7's new switch statement, and while it's awesome that I can switch on the type as part of pattern matching, I wonder if I can avoid re-stating the type in case I already know it?
Example:
private static void BetterSwitchCase(string s)
{
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;
default:
Console.WriteLine("No Match.");
break;
}
}
Here, my case statement re-states string x even though the type I'm switching on is already a string, and I only care about it's Length and if it int.TryParses.
Just omitting it doesn't compile:
// Syntax error, ':' expected
case when s.Length == 3 && int.TryParse(s, out int i):
// A constant value is expected
case s when s.Length == 3 && int.TryParse(s, out int i):
So I'm just wondering if there is a way to omit it, or if it's just part of the pattern matching syntax that I have to accept.
You could use var pattern:
case var x when x.Length == 3 && int.TryParse(x, out int i):
Or even better, var pattern with a discard:
case var _ when s.Length == 3 && int.TryParse(s, out int i):
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
I've used the following. Aesthetically it is displeasing, but it does have two advantages. It's fairly easy to understand and it compiles. The x ends up not being used. The variable in the switch statement can be a dummy. If you have particularly complicated heavily nested if-then code this method can be used and can be easier to /read/understand. Anyone know a better way?
switch (dummyString)
{
case string x1 when word = "entry":
DoEntry();
break;
case string x2 when word = "exit" && door="front":
DoFrontDoorExit();
break;
case string x3 when word = "exit" && door="rear":
DoRearDoorExit();
break;
case string x4 when Tomorrow() == "Tuesday":
BuyALotteryTicket()
break;
default:
break;
}

Converting function to determine operator precedence from C# to C++

I need to convert some code from C# to C/C++. The effect of the function is to determine operator precedence for math evaluations.
private static int OperatorPrecedence(string strOp)
{
switch (strOp)
{
case "*":
case "/":
case "%": return 0;
case "+":
case "-": return 1;
case ">>":
case "<<": return 2;
case "<":
case "<=":
case ">":
case ">=": return 3;
case "==":
case "=":
case "!=": return 4;
case "&": return 5;
case "^": return 6;
case "|": return 7;
case "&&": return 8;
case "||": return 9;
}
throw new ArgumentException("Operator " + strOp + "not defined.");
}
I realize the numerous questions about strings in switch statements in C++, but that's not really what I'm asking. Obviously the switch(string) syntax is not legal in C++. I don't want to use it. I just need an efficient way to determine the precedence of the above operators short of initializing an entire map at the start of the program or large if-else chains (which is really just dancing around the swiitch statement).
Any ideas how I can determine operator precedence? Maybe a way to generate a unique code for each operator?
As specified in this C# answer a switch with a string is compiled into a dictionary lookup or a if-else chain depending on the amount of cases.
The dictionary type in C++ is std::map, you could use a static dictionary in a scope and then search in it.
So a straight equivalent, 1:1 conversion, would be something along those lines:
int OperatorPrecedence(const std::string& strOp)
{
static std::map<std::string, int> lookup = { {"*", 1}, {"/", 1} /* add more */ };
auto it = lookup.find(strOp);
if(it != lookup.end())
return it->second;
else
throw std::invalid_argument(std::string("Operator ") + strOp + "not defined");
}
The advantage of using a statically stored dictionary instead of one with automatic storage duration here is that the container does not to be initialized (allocations!) every time you ask for OperatorPrecedence.

Not all code paths return a value - but they do

The following extract of code is failing to compile resulting in not code paths return a value. Both types Test1StandardChargeCalculator and Test2StandardChargeCalculator are derived from the return type.
I know how to fix this, but my question is why should I have to? A bool is a value type - hence can only represent true or false, both of which are catered for in this snippet. So why the failed compilation?
internal StandardChargeCalculator Create()
{
bool value = true;
switch (value)
{
case true:
return new Test1StandardChargeCalculator();
case false:
return new Test2StandardChargeCalculator();
}
} //not all code paths return a value
When using a switch statement, the compiler does not understand that when you are using a boolean type to switch on there can only be two results.
The error occurs because you do not have a default case.
Don't use a switch for boolean test - use an if statement:
bool value = true;
if(value)
{
return new Test1StandardChargeCalculator();
}
return new Test2StandardChargeCalculator();
Why do you think the compiler should special-case boolean and detect that all possible values have a case statement?
If you were writing a compiler, would you invest development effort and increase the risk of bugs by implementing this?
In Absence of evidence is not evidence of absence Eric Lippert writes about the limitations of 'proofing' that a variable is unassigned and the weaker aim of the compiler in this regard:
that we're not interested in proving for certain that x is unassigned.
We're interested in proving for certain that x is assigned! If we can
prove that for certain, then x is "definitely assigned". If we cannot
prove that for certain then x is "not definitely assigned".
Which does not directly explain this example but note that it is the same issue as :
int x;
if (a < 10)
x = 0;
else if (a >= 10)
x = 1;
y = x; // x is 'unassigned'
We can quickly see that x will always be assigned, the compiler does not even attempt to find out.
To my understanding it is inconsistant to the definition of the switch which says:
If no case expression matches the switch value, then control is transferred to the statement(s) that follow the optional default label. If there is no default label, control is transferred outside the switch.
You are right: there should be no compiler error. So, this might be a case where no answer is the answer. You will have to live with it.
switch (answer)
{
...
default:
return "It is as it is"
}
Maybe better solution would be
internal StandardChargeCalculator Create()
{
StandardChargeCalculator result = null;
bool value = true;
switch (value)
{
case true:
result = new Test1StandardChargeCalculator();
break;
case false:
result = new Test2StandardChargeCalculator();
break;
}
return result;
}

Multiple cases in switch statement

Is there a way to fall through multiple case statements without stating case value: repeatedly?
I know this works:
switch (value)
{
case 1:
case 2:
case 3:
// Do some stuff
break;
case 4:
case 5:
case 6:
// Do some different stuff
break;
default:
// Default stuff
break;
}
but I'd like to do something like this:
switch (value)
{
case 1,2,3:
// Do something
break;
case 4,5,6:
// Do something
break;
default:
// Do the Default
break;
}
Is this syntax I'm thinking of from a different language, or am I missing something?
I guess this has been already answered. However, I think that you can still mix both options in a syntactically better way by doing:
switch (value)
{
case 1: case 2: case 3:
// Do Something
break;
case 4: case 5: case 6:
// Do Something
break;
default:
// Do Something
break;
}
There is no syntax in C++ nor C# for the second method you mentioned.
There's nothing wrong with your first method. If however you have very big ranges, just use a series of if statements.
Original Answer for C# 7
In C# 7 (available by default in Visual Studio 2017/.NET Framework 4.6.2), range-based switching is now possible with the switch statement and would help with the OP's problem.
Example:
int i = 5;
switch (i)
{
case int n when (n >= 7):
Console.WriteLine($"I am 7 or above: {n}");
break;
case int n when (n >= 4 && n <= 6 ):
Console.WriteLine($"I am between 4 and 6: {n}");
break;
case int n when (n <= 3):
Console.WriteLine($"I am 3 or less: {n}");
break;
}
// Output: I am between 4 and 6: 5
Notes:
The parentheses ( and ) are not required in the when condition, but are used in this example to highlight the comparison(s).
var may also be used in lieu of int. For example: case var n when n >= 7:.
Updated examples for C# 9
switch(myValue)
{
case <= 0:
Console.WriteLine("Less than or equal to 0");
break;
case > 0 and <= 10:
Console.WriteLine("More than 0 but less than or equal to 10");
break;
default:
Console.WriteLine("More than 10");
break;
}
or
var message = myValue switch
{
<= 0 => "Less than or equal to 0",
> 0 and <= 10 => "More than 0 but less than or equal to 10",
_ => "More than 10"
};
Console.WriteLine(message);
This syntax is from the Visual Basic Select...Case Statement:
Dim number As Integer = 8
Select Case number
Case 1 To 5
Debug.WriteLine("Between 1 and 5, inclusive")
' The following is the only Case clause that evaluates to True.
Case 6, 7, 8
Debug.WriteLine("Between 6 and 8, inclusive")
Case Is < 1
Debug.WriteLine("Equal to 9 or 10")
Case Else
Debug.WriteLine("Not between 1 and 10, inclusive")
End Select
You cannot use this syntax in C#. Instead, you must use the syntax from your first example.
With C#9 came the Relational Pattern Matching. This allows us to do:
switch (value)
{
case 1 or 2 or 3:
// Do stuff
break;
case 4 or 5 or 6:
// Do stuff
break;
default:
// Do stuff
break;
}
In deep tutorial of Relational Patter in C#9
Pattern-matching changes for C# 9.0
Relational patterns permit the programmer to express that an input
value must satisfy a relational constraint when compared to a constant
value
You can leave out the newline which gives you:
case 1: case 2: case 3:
break;
but I consider that bad style.
.NET Framework 3.5 has got ranges:
Enumerable.Range from MSDN
you can use it with "contains" and the IF statement, since like someone said the SWITCH statement uses the "==" operator.
Here an example:
int c = 2;
if(Enumerable.Range(0,10).Contains(c))
DoThing();
else if(Enumerable.Range(11,20).Contains(c))
DoAnotherThing();
But I think we can have more fun: since you won't need the return values and this action doesn't take parameters, you can easily use actions!
public static void MySwitchWithEnumerable(int switchcase, int startNumber, int endNumber, Action action)
{
if(Enumerable.Range(startNumber, endNumber).Contains(switchcase))
action();
}
The old example with this new method:
MySwitchWithEnumerable(c, 0, 10, DoThing);
MySwitchWithEnumerable(c, 10, 20, DoAnotherThing);
Since you are passing actions, not values, you should omit the parenthesis, it's very important. If you need function with arguments, just change the type of Action to Action<ParameterType>. If you need return values, use Func<ParameterType, ReturnType>.
In C# 3.0 there is no easy Partial Application to encapsulate the fact the the case parameter is the same, but you create a little helper method (a bit verbose, tho).
public static void MySwitchWithEnumerable(int startNumber, int endNumber, Action action){
MySwitchWithEnumerable(3, startNumber, endNumber, action);
}
Here an example of how new functional imported statement are IMHO more powerful and elegant than the old imperative one.
Here is the complete C# 7 solution...
switch (value)
{
case var s when new[] { 1,2,3 }.Contains(s):
// Do something
break;
case var s when new[] { 4,5,6 }.Contains(s):
// Do something
break;
default:
// Do the default
break;
}
It works with strings too...
switch (mystring)
{
case var s when new[] { "Alpha","Beta","Gamma" }.Contains(s):
// Do something
break;
...
}
The code below won't work:
case 1 | 3 | 5:
// Not working do something
The only way to do this is:
case 1: case 2: case 3:
// Do something
break;
The code you are looking for works in Visual Basic where you easily can put in ranges... in the none option of the switch statement or if else blocks convenient, I'd suggest to, at very extreme point, make .dll with Visual Basic and import back to your C# project.
Note: the switch equivalent in Visual Basic is Select Case.
Another option would be to use a routine. If cases 1-3 all execute the same logic then wrap that logic in a routine and call it for each case. I know this doesn't actually get rid of the case statements, but it does implement good style and keep maintenance to a minimum.....
[Edit] Added alternate implementation to match original question...[/Edit]
switch (x)
{
case 1:
DoSomething();
break;
case 2:
DoSomething();
break;
case 3:
DoSomething();
break;
...
}
private void DoSomething()
{
...
}
Alt
switch (x)
{
case 1:
case 2:
case 3:
DoSomething();
break;
...
}
private void DoSomething()
{
...
}
In C# 7 we now have Pattern Matching so you can do something like:
switch (age)
{
case 50:
ageBlock = "the big five-oh";
break;
case var testAge when (new List<int>()
{ 80, 81, 82, 83, 84, 85, 86, 87, 88, 89 }).Contains(testAge):
ageBlock = "octogenarian";
break;
case var testAge when ((testAge >= 90) & (testAge <= 99)):
ageBlock = "nonagenarian";
break;
case var testAge when (testAge >= 100):
ageBlock = "centenarian";
break;
default:
ageBlock = "just old";
break;
}
One lesser known facet of switch in C# is that it relies on the operator= and since it can be overriden you could have something like this:
string s = foo();
switch (s) {
case "abc": /*...*/ break;
case "def": /*...*/ break;
}
gcc implements an extension to the C language to support sequential ranges:
switch (value)
{
case 1...3:
//Do Something
break;
case 4...6:
//Do Something
break;
default:
//Do the Default
break;
}
Edit: Just noticed the C# tag on the question, so presumably a gcc answer doesn't help.
I think this one is better in C# 7 or above.
switch (value)
{
case var s when new[] { 1,2 }.Contains(s):
// Do something
break;
default:
// Do the default
break;
}
You can also check Range in C# switch case: Switch case: can I use a range instead of a one number
OR
int i = 3;
switch (i)
{
case int n when (n >= 7):
Console.WriteLine($"I am 7 or above: {n}");
break;
case int n when (n >= 4 && n <= 6):
Console.WriteLine($"I am between 4 and 6: {n}");
break;
case int n when (n <= 3):
Console.WriteLine($"I am 3 or less: {n}");
break;
}
Switch case multiple conditions in C#
Or if you want to understand basics of
C# switch case
Actually I don't like the GOTO command too, but it's in official Microsoft materials, and here are all allowed syntaxes.
If the end point of the statement list of a switch section is reachable, a compile-time error occurs. This is known as the "no fall through" rule. The example
switch (i) {
case 0:
CaseZero();
break;
case 1:
CaseOne();
break;
default:
CaseOthers();
break;
}
is valid because no switch section has a reachable end point. Unlike C and C++, execution of a switch section is not permitted to "fall through" to the next switch section, and the example
switch (i) {
case 0:
CaseZero();
case 1:
CaseZeroOrOne();
default:
CaseAny();
}
results in a compile-time error. When execution of a switch section is to be followed by execution of another switch section, an explicit goto case or goto default statement must be used:
switch (i) {
case 0:
CaseZero();
goto case 1;
case 1:
CaseZeroOrOne();
goto default;
default:
CaseAny();
break;
}
Multiple labels are permitted in a switch-section. The example
switch (i) {
case 0:
CaseZero();
break;
case 1:
CaseOne();
break;
case 2:
default:
CaseTwo();
break;
}
I believe in this particular case, the GOTO can be used, and it's actually the only way to fallthrough.
Source
In C# 8.0 you can use the new switch expression syntax which is ideal for your case.
var someOutput = value switch
{
>= 1 and <= 3 => <Do some stuff>,
>= 4 and <= 6 => <Do some different stuff>,
_ => <Default stuff>
};
If you have a very big amount of strings (or any other type) case all doing the same thing, I recommend the use of a string list combined with the string.Contains property.
So if you have a big switch statement like so:
switch (stringValue)
{
case "cat":
case "dog":
case "string3":
...
case "+1000 more string": // Too many string to write a case for all!
// Do something;
case "a lonely case"
// Do something else;
.
.
.
}
You might want to replace it with an if statement like this:
// Define all the similar "case" string in a List
List<string> listString = new List<string>(){ "cat", "dog", "string3", "+1000 more string"};
// Use string.Contains to find what you are looking for
if (listString.Contains(stringValue))
{
// Do something;
}
else
{
// Then go back to a switch statement inside the else for the remaining cases if you really need to
}
This scale well for any number of string cases.
You can also have conditions that are completely different
bool isTrue = true;
switch (isTrue)
{
case bool ifTrue when (ex.Message.Contains("not found")):
case bool ifTrue when (thing.number = 123):
case bool ifTrue when (thing.othernumber != 456):
response.respCode = 5010;
break;
case bool ifTrue when (otherthing.text = "something else"):
response.respCode = 5020;
break;
default:
response.respCode = 5000;
break;
}
An awful lot of work seems to have been put into finding ways to get one of C# least used syntaxes to somehow look better or work better. Personally I find the switch statement is seldom worth using. I would strongly suggest analyzing what data you are testing and the end results you are wanting.
Let us say for example you want to quickly test values in a known range to see if they are prime numbers. You want to avoid having your code do the wasteful calculations and you can find a list of primes in the range you want online. You could use a massive switch statement to compare each value to known prime numbers.
Or you could just create an array map of primes and get immediate results:
bool[] Primes = new bool[] {
false, false, true, true, false, true, false,
true, false, false, false, true, false, true,
false,false,false,true,false,true,false};
private void button1_Click(object sender, EventArgs e) {
int Value = Convert.ToInt32(textBox1.Text);
if ((Value >= 0) && (Value < Primes.Length)) {
bool IsPrime = Primes[Value];
textBox2.Text = IsPrime.ToString();
}
}
Maybe you want to see if a character in a string is hexadecimal. You could use an ungly and somewhat large switch statement.
Or you could use either regular expressions to test the char or use the IndexOf function to search for the char in a string of known hexadecimal letters:
private void textBox2_TextChanged(object sender, EventArgs e) {
try {
textBox1.Text = ("0123456789ABCDEFGabcdefg".IndexOf(textBox2.Text[0]) >= 0).ToString();
} catch {
}
}
Let us say you want to do one of 3 different actions depending on a value that will be the range of 1 to 24. I would suggest using a set of IF statements. And if that became too complex (Or the numbers were larger such as 5 different actions depending on a value in the range of 1 to 90) then use an enum to define the actions and create an array map of the enums. The value would then be used to index into the array map and get the enum of the action you want. Then use either a small set of IF statements or a very simple switch statement to process the resulting enum value.
Also, the nice thing about an array map that converts a range of values into actions is that it can be easily changed by code. With hard wired code you can't easily change behaviour at runtime but with an array map it is easy.
A more beautiful way to handle that
if ([4, 5, 6, 7].indexOf(value) > -1)
//Do something
You can do that for multiple values with the same result
Just to add to the conversation, using .NET 4.6.2 I was also able to do the following.
I tested the code and it did work for me.
You can also do multiple "OR" statements, like below:
switch (value)
{
case string a when a.Contains("text1"):
// Do Something
break;
case string b when b.Contains("text3") || b.Contains("text4") || b.Contains("text5"):
// Do Something else
break;
default:
// Or do this by default
break;
}
You can also check if it matches a value in an array:
string[] statuses = { "text3", "text4", "text5"};
switch (value)
{
case string a when a.Contains("text1"):
// Do Something
break;
case string b when statuses.Contains(value):
// Do Something else
break;
default:
// Or do this by default
break;
}
We can also use this approach to achieve Multiple cases in switch statement... You can use as many conditions as you want using this approach..
int i = 209;
int a = 0;
switch (a = (i>=1 && i<=100) ? 1 : a){
case 1:
System.out.println ("The Number is Between 1 to 100 ==> " + i);
break;
default:
switch (a = (i>100 && i<=200) ? 2 : a) {
case 2:
System.out.println("This Number is Between 101 to 200 ==> " + i);
break;
default:
switch (a = (i>200 && i<=300) ? 3 : a) {
case 3:
System.out.println("This Number is Between 201 to 300 ==> " + i);
break;
default:
// You can make as many conditions as you want;
break;
}
}
}
Using new version of C# I have done in this way
public string GetValue(string name)
{
return name switch
{
var x when name is "test1" || name is "test2" => "finch",
"test2" => somevalue,
_ => name
};
}
For this, you would use a goto statement. Such as:
switch(value){
case 1:
goto case 3;
case 2:
goto case 3;
case 3:
DoCase123();
//This would work too, but I'm not sure if it's slower
case 4:
goto case 5;
case 5:
goto case 6;
case 6:
goto case 7;
case 7:
DoCase4567();
}

Categories