I have the following reasonably simple switch statement.
// earlier
string fullPath = GetFullPath();
string type = GetEntityType();
switch (type.ToLower()) {
case "tables":
tables.Add(fullPath);
break;
case "views":
views.Add(fullPath);
break;
case "functions":
functions.Add(fullPath);
break;
case "storedprocs":
storedprocs.Add(fullPath);
break;
case "data":
data.Add(fullPath);
break;
case "layouts":
layouts.Add(fullPath);
break;
case "scripts":
scripts.Add(fullPath);
break;
default:
Console.WriteLine($"What is this: {type}");
break;
}
When I decompile the resulting binary using Reflector, the switch(string) has been changed to ComputeStringHash and then inside each case statement it checks the value via the if statement. Sounds like it's doing double the work.
string s = str2.ToLower();
switch (<PrivateImplementationDetails>.ComputeStringHash(s))
{
case 0x20890fc4:
if (s == "tables")
{
break;
}
goto Label_0218;
case 0x454a414e:
if (s == "functions")
{
goto Label_01DE;
}
goto Label_0218;
case 0x4facf6d1:
if (s == "views")
{
goto Label_01D3;
}
goto Label_0218;
case 0xcdfe2cb3:
if (s == "storedprocs")
{
goto Label_01E9;
}
goto Label_0218;
case 0xd872e2a5:
if (s == "data")
{
goto Label_01F4;
}
goto Label_0218;
case 0x9b4a129b:
if (s == "scripts")
{
goto Label_020C;
}
goto Label_0218;
case 0xba971064:
if (s == "layouts")
{
goto Label_0200;
}
goto Label_0218;
default:
goto Label_0218;
}
first.Add(fullPath);
continue;
Label_01D3:
second.Add(fullPath);
continue;
Label_01DE:
list3.Add(fullPath);
continue;
Label_01E9:
list4.Add(fullPath);
continue;
Label_01F4:
list5.Add(fullPath);
continue;
Label_0200:
list6.Add(fullPath);
continue;
Label_020C:
list7.Add(fullPath);
continue;
Label_0218:
Console.WriteLine("What is this: " + str2);
}
This is a very smart optimization, which lets the switch do its job in time that is almost independent of the number of strings in the case block of the statement.
This optimization is based on the observation that hash codes of identical strings must be the same. Rather than checking strings for equality one-by-one, the compiler computes a hash of the target string once, and performs a table-based lookup in O(1). This gets the compiler to the desired case, at which point the compiler needs to check that the strings are actually equal.
Note that there would be some rare situations when multiple look-up strings would have the same hash code. In such situations the generated case statement would contain multiple if to decide among the strings with equal hash codes.
Overall, this behavior mimics the behavior of hash-based dictionaries: hash code determines the case (an equivalent of a hash bucket) and the series of ifs inside determines if there is a match. This results in a better performance, because it lets the compiler skip the unnecessary checks.
Related
I'm trying to learn programming C# (self taught) and I came to a point where I don't know if switch case can be used like if condition.
Can I make a comparison with switch like this?
switch(var)
{
case var < 10:
//Do something
break;
}
Or this is a case of why if condition is different compared to switch?
Certain comparisons can be done in switch cases via patterns. In your specific scenario, a relational pattern could check if a switch input is < 10.
switch(var)
{
case < 10:
//Do something
break;
}
One significant limitation of patterns is that the values inside them have to be constant. So if you had a variable int x and tried to use it in case < x: it wouldn't work.
https://dotnetcoretutorials.com/2020/08/10/relational-pattern-matching-in-c-9/
Deciding if to use an IF statement or SWITCH statement depends on a number of factors, including the readability of your code. There are times when multiple IF statements provide a more simpler approach than using switch. Other times it would be best to use a switch statement.
The simple answer to your question is yes but it would be best for you to try both in a particular scenario if you want to learn.
For most purposes switch is an alternative way to write an chain of if/else statement
switch(myVar)
{
case 1:
//Do something
break;
case 2:
//Do something
break;
case 3:
//Do something
break;
default:
//Do something else
}
Is equivalent to
if(myVar == 1) {
//Do something
}
else if(myVar == 2) {
//Do something
}
else if(myVar == 3) {
//Do something
}
else {
//Do something
}
In older versions of C# (pre 7.0) case statements were restricted to only testing if values were equal to a constant. However with the introduction of a feature called 'pattern matching' you can do more expressive matches within case statements. Subsequent C# versions have added more and more syntax in this area, but ultimately they don't do anything beyond what can be achieved with an if/else chain. For situations where there are a lot of conditions the switch/case statements are typically easier to read
An example of changes in syntax being allowed C# 9.0
switch(myVar)
{
case == 1:
//Do something
break;
case > 1 and < 3:
//Do something
break;
case == 3:
//Do something
break;
default:
//Do something else
}
I am a beginner in learning c# (and any coding language)
I am trying to use switch statement instead of if else.
this is the working if else statement
private void RunScript(int a, int b, ref object A)
{
if (a < b)
{
Print("a is smaller than b");
Print("b is bigger than a");
}
else if (a > b)
{
Print("a is bigger than b");
Print("b is smaller than a");
}
else
{
Print("a equals b");
}
this is the switch that I am trying to do
private void RunScript(double a, double b, ref object A)
{
double whichIsBigger = a - b;
//below is the 58th line
switch (whichIsBigger)
{
case whichIsBigger < 0:
Print("a is bigger than b");
break;
case whichIsBigger > 0:
Print("a is smaller than b");
break;
default:
Print("a equals b");
break;
}
It gives me this
Error (CS0151): A switch expression or case label must be a bool, char, string, integral, enum, or corresponding nullable type (line 58)
FYI, I'm trying to do this on rhinoceros3d, using the rhino common library.
and also, I've been trying to find a website or forum to learn c# where I can
ask questions like these. I ended up here.
I think that this kind of questions is pretty basic, but I can't find a
resource that can give me an answer to this problem.
I have read several posts and can't find a similar problem
If there are any sites where people can answer my questions fast like a chat room or something,
please do let me know.
Basically, you're trying to run an evaluation in your case statement. You have to do the evaluation before, and use the values in your case statement.
If it's a true / false situation, you shouldn't use switch. Switch is generally for when there are a number of options that could be true. For example, if you had an enum with multiple values, and you want to do something different for each value (like DayOfWeek.Monday, DayOfWeek.Tuesday, etc). For the exact reason you're running into here.
If you really wanted, you could create an enum of ABCompare.Bigger, ABCompare.Smaller, ABCompare.Equal or something like that, and then switch on that -- but that doesn't really make sense.
The switch statement works by comparing the value you pass in to a list of alternatives you provide. So, you can do:
switch (a < b)
{
case true:
// do some stuff
break;
case false:
switch (a > b)
{
case true:
// do other stuff
break;
case false:
// do other other stuff
break;
}
break;
}
but you can't do direct comparisons in the case statement because they're already doing a comparison with the value you passed into the original switch.
Also, the afore-mentioned example is a poor use case for switch as it would be better-handled by an if-else. If your goal is to understand switch, my advice would be to try converting an enum to some other type based on its values:
public enum Color
{
Red,
Blue,
Green,
}
public string ConvertToHexWithIfElse(Color myColor)
{
if (myColor == Color.Red)
{
return "#FF0000";
}
else if (myColor == Color.Green)
{
return "#00FF00";
}
else if (myColor == Color.Blue)
{
return "#0000FF";
}
return string.Empty;
}
public string ConvertToHexWithSwitch(Color myColor)
{
switch (myColor)
{
case Color.Red:
return "#FF0000";
case Color.Blue:
return "#0000FF";
case Color.Green:
return "#00FF00";
default:
return string.Empty;
}
}
Note that even this example is somewhat of a poor use of switch because the enum was a forced contrivance used simply to show the usage. IMHO switch doesn't have many actual uses: you either use a dictionary or you use an if-else.
When doing a switch statement each "case" is not supposed to have a conditional in it. Switch statements are designed to "switch" values. Like for example, swapping colors!
Color c = (Color) (new Random()).Next(0, 3);
switch (c)
{
//Value of "c" is red
case Color.Red:
Console.WriteLine("Red!");
break;
//Value of "c" is green
case Color.Green:
Console.WriteLine("Green!");
break;
//Value of "c" is blue
case Color.Blue:
Console.WriteLine("Blue!");
break;
//"c" is not red, green, or blue, so we default our message to say the color is unknown!
default:
Console.WriteLine("The color is not known.");
break;
}
In each "case" we see if "c" is a specific value, and if not, we have a default in our switch statement to handle the scenario.
So I was making a Rock Paper Scissor game and I've sort of made adjustments to it to include life and other things. Now I got stuck with the switch statement. My if statement works fine:
private void Result_TextChanged(object sender, EventArgs e)
{
if (playerscore == 1 || pcscore == 1)
{
PlayerLife.Image = Properties.Resources.Five;
}
}
I was wondering how I could translate this to the switch statement?
private void Result_TextChanged(object sender, EventArgs e)
{
switch (playerscore || pcscore)
{
case 1:
PlayerLife.Image = Properties.Resources.Five;
break;
}
}
Doesn't seem to work.
The simple answer is No. You cant use it like that.
Switch works with single expression.
You may check MSDN for details.
You may try like this:-
if (playerscore == pcscore)
{
switch (playerscore)
{
case 1:
PlayerLife.Image = Properties.Resources.Five;
break;
}
}
EDIT:-
As commented by Jeppe Stig Nielsen in the comments, You can switch on any expression of a suitable type. That expression may contain ||. There can be many case labels associated with each switch section in a switch block.
But personally speaking that would not be a good practice to follow. You may try to use if statement for that.
You may try like this if you want:
switch (playerscore == 1 || pcscore == 1)
In C#, a switch statement resolves a single expression and compares that value with a list of possible cases:
switch(someExpression)
{
case x: // This runs if someExpression == x
break;
case y: // This runs if someExpression == y
break;
}
Now, you could switch on the expression (playerscore == 1 || pcscore == 1) like so:
switch(playerscore == 1 || pcscore == 1) // This expression is either true or false
{
case true: // Runs if playerscore is 1 or pcscore is 1
break;
case false: // runs if neither playscore or pcscore are 1
break;
}
However, the above is rather unreadable and silly. You'd be best off with the if statement:
if(playerscore == 1 || pcscore == 1)
{
// Runs if playerscore is 1 or pcscore is 1
}
else
{
// runs if neither playscore or pcscore are 1
}
You could write it like this but why would you want to?
switch (playerscore == 1 || pcscore == 1)
{
case true:
PlayerLife.Image = Properties.Resources.Five;
break;
default:
break;
}
As Jeppe points out in the comment below, when you use || or && you end up with a bool and an if statement should be used.
Here is a great answer by #EricLippert on what can be used as the expression in a swtich statement.
What you are trying to do doesn't make sense, if playerscore = 3 and pcscore = 2 then what would playerscore || pcscore be equal to?
If you have a whole bunch of variables, say not just two, but 5, 10, or even an unknown number, then what you can do is put all of the values that you want to compare to 1 into a collection and then act on that collection as a whole.
//this could just be a list/array accepted as a paramter,
//can include other variables, or whatever
var scores = new []{playerscore, pcscore};
if(scores.Any(score => score == 1))
PlayerLife.Image = Properties.Resources.Five;
switch isn't really an appropriate tool for manipulating collections like this.
This makes no sense: in a switch statement you always want to compare with a specific type, rather than to a boolean value as follows:
switch (playerscore || pcscore)
in your case use the 'if'-statement
Suppose that playerscore and pcscore are integer who has 0 or 1 as possible values
resp = playerscore + 10 * pcscore;
switch (resp)
{
case 0:
// both are false
break;
case 1:
// playerscore true
break;
case 10:
// pcscore true
break;
case 11:
// both are true
break;
default:
// error in input data
break;
}
switch ("Case2")
{
case (string)Application.Current.FindResource("Case1");
//Do Some logic
break;
case (string)Application.Current.FindResource("Case2");
//Do Some logic
break;
case (string)Application.Current.FindResource("Case3");
//Do Some logic
break;
default:
break;
}
I did this code But it is not work. Now i want to assign the string value((string)Application.Current.FindResource("Case1")) which getting from resource dictionary to constant expression.How is it possible or else is there any way ?
It is not possible. A constant expression is, by definition, a compile-time constant. A resource dictionary lookup must happen at run time. The usual solution is to use a string of if statements:
if ("Case2" == (string)Application.Current.FindResource("Case1"))
{
//Do some logic
}
else if ("Case2" == (string)Application.Current.FindResource("Case2"))
{
//Do some logic
}
else if ("Case2" == (string)Application.Current.FindResource("Case3"))
{
//Do some logic
}
I have two questions with this code:
public int InsertOrUpdateRecord(char _code, string _databaseFileName)
{
switch(_code)
{
case 'N':
// Some code here
case 'U':
// Some code here
}
return 0;
}
It is not accepting char single quote and double quote value.
If I pass _code as string, it gives red underline in case with this error:
Control cannot fall through one case label to another.
The reason for the compilation error is that the case is missing the break
switch (_code)
{
case 'N':
// Some code here
break; // break that closes the case
case 'U':
// Some code here
break; // break that closes the case
}
You need to do a break at the end of the case:
switch (_code)
{
case 'N':
// Some code here
Console.WriteLine("N was passed");
break;
case 'U':
// Some code here
Console.WriteLine("U was passed");
break;
}
Unless you want in either cases to do the same like so:
switch(_char) {
case 'N':
case 'U':
// Common code for cases N and U here...
}
You have to specifically tell the compiler where the case statement halts:
switch(_char) {
case 'N':
// Code here...
break; // The N case ends here.
case 'U':
// Code here with different behaviour than N case...
break; // The U case ends here.
}
The break statement tells the compiler that you're done with that case, and that it has to get out of the switch instruction.
you can either write a break or return statement like the below code.
char _code = 'U';
switch (_code)
{
case 'N':
case 'U':
return;
}
OR,
char _code = 'u';
switch (_code)
{
case 'N':
case 'U':
break;
}
There is no problem with char. See this msdn article about your error.