Can you create a switch with multiple expressions? - c#

I was wondering if I can use a switch with multiple expressions. For example:
string s = "A";
int i = 3;
switch (s, i)
{
case "A", 1:
//DoStuff
break;
case "A", 2:
//DoStuff
break;
case "A", 3:
//DoStuff
break;
...
}
I don't want to use hundreds of if(s == "A" && i == 1)-Statements so it would be great if there's a better solution.
PS: This switch is just an example, I'm actually using it with more complex strings like Names

You certainly can, for example by using tuples:
string s = "A";
int i = 3;
switch (s, i)
{
case ("A", 1):
// DoStuff.
break;
case ("A", 2):
// DoStuff.
break;
case ("A", 3):
// DoStuff.
break;
}
(Basically exactly what you typed, except with the addition of parenthesis in the cases to make them into tuples.)
Note that this requires C# 7 or later.

Since C# 7, it is possible to do the following:
string s = "A";
int i = 3;
switch (s)
{
case "A" when i == 1:
//DoStuff
break;
case "A" when i == 2:
//DoStuff
break;
case "A" when i == 3:
//DoStuff
break;
...
}

Related

How to minimize this switch?

switch(number){
case 2:
a+=b;
break;
case 3:
a+=b;
break;
case 4:
a+=b;
d=f;
break;
case 5:
d=e;
break;
}
how to minimize first three switch cases which which does similar work?
If you using C# 7, you can make use of Pattern Matching, even though this is an overkill as rightly pointed by Jon Skeet. But in case, you want to stick to switch case, and want to reduce 'case', you could do the following
switch(number)
{
case var _ when number == 2 || number==3 || number==4:
a+=b;
if(number ==4)
d=f
break;
case 5:
d=e;
break;
}
You can also replace the first case with variants like
case var _ when new[]{2,3,4}.Contains(number):
Or
case var _ when number >= 2 || number <= 3: // As pointed by earlier answer
Without pattern matching, you could do the following as well
switch(number)
{
case 2:
case 3:
case 4:
a+=b;
if(number ==4)
d=f;
break;
case 5:
d = e;
break;
}
Btw, if your problem is "a+b" is about 60 lines of code, you always have the option to make it a function (and move it out of switch case) to increase its readability.
switch(number)
{
case 2:
case 3:
case 4:
MethodAbAction();
if(number ==4)
MethodDFAction();
break;
case 5:
MethodDEAction();
break;
}
btw, a 60 line method is never fun to read. It would be better if you can split up.
if (2 <= number && number <= 4) {
a += b;
}
if (number == 4) {
d = f;
} else if (number == 5) {
d = e;
}
if (number != 5)
{
a += b;
}
if (number == 4)
{
d = f;
}
else
if (number == 5)
{
d = e;
}

Checking case in multiple case statement

Consider following case statement
Case 'A':
break;
Case 'B':
Case 'C':
// some logic
int i = 0;
// here I need i =5 (if case id 'B') and i=10 (if case is 'C')
// Rest of the logic is same
break;
I know I can achieve this by writing seperate case for 'B' and 'C' and writing rest of the logic in a seperate function and call that function in 'B' and 'C' case.
But is there any way, I can check the case in Case statement only ... as follows
Case 'B':
Case 'C':
// Can I check here
// if (case == 'B')
// i = 5;
// if (case == 'C')
// i = 10;
// Rest of the logic
I tried the following which worked without any problems:
switch (a)
{
case 'A':
Console.WriteLine("Es ist ein 'A'.");
break;
case 'B':
case 'C':
if (a == 'B')
Console.WriteLine("Es ist ein 'B'.");
if (a == 'C')
Console.WriteLine("Es ist ein 'C'.");
break;
}
But if you're just checking if it's 'B' or 'C', I would suggest writing two separate cases.
Put your //Rest of Logic inside a new method, and do separate test cases for a neater code:
private void DoSomething(int i)
{
//Rest of Logic
}
public void SwitchMethod(char input)
{
int i = 0;
Switch (input)
{
case 'A':
break;
case 'B':
i = 5;
DoSomething(i);
break;
case 'C':
i = 10;
DoSomething(i);
break;
}
}

Switch case goes to default except one case

when i tried to use the Switch case function, it goes always to the default message besides case 5:
private void btnCandlesLight_Click(object sender, EventArgs e)
{
int result;
result = Convert.ToInt32(textBox1.Text);
switch(result)
{
case 1:
day1.Start();
candlesOne();
break;
case 2:
day2.Start();
candlesTwo();
break;
case 3:
day3.Start();
candlesThree();
break;
case 4:
day4.Start();
candlesFour();
break;
case 5:
day5.Start();
candlesFive();
break;
case 6:
day6.Start();
candlesSix();
break;
case 7:
day7.Start();
candlesSeven();
break;
case 8:
day8.Start();
candlesEight();
break;
default:
MessageBox.Show("Enter new day");
break;
}
}
When I Enter the value 1 for example to the text box, the default case works, but only when I enter the value 5 it works perfectly.
If you want to see the difference between the function "candlesOne" to "candlesFive":
The "c" variable is a variable of the seconds. i tried to use a timer in a way of lighting up the candles every 2-3 seconds.
public void candlesOne()
{
firedmatch.Left = firedmatch.Left + 100;
if (c == 1)
{
candle1.Visible = true;
}
if (c == 3)
{
candle2.Visible = true;
}
}
and:
public void candlesFive()
{
firedmatch.Left = firedmatch.Left + 100;
if(c == 1)
{
candle1.Visible = true;
}
if(c == 3)
{
candle2.Visible = true;
}
if(c == 5)
{
candle3.Visible = true;
}
if(c == 7)
{
candle4.Visible = true;
}
if(c == 11)
{
candle5.Visible = true;
}
}
I haven't found a mistake,
can you guys help me?
Thanks
Have you checked if you really get for example (int)1 as a result of the "1" input from your conversion?
On a broader scale, there is a lot of repetition in your code, you should consider refactoring it a little.
In your CandlesOne and CandlesFive methods, you use a c variable, no idea what that is or where it comes from. Those two methods (and probably the other CandlesXXX() do the same kind of things. Can't you remove complexity by generalizing the logic? Can the result used in your switch-case be passed as a parameter and used to trigger the numbers of c == X calls in the CandleXXX() methods?
This way you could remove the switch and lose a lot of complexity!
Edit
If you have further problems, consider creating a .NET Fiddle, I miss a lot of context in your code so I cannot efficiently help you here.
Some refactoring ideas for you:
// Somewhere else in your code, create a dictionary with your day1-day8 objects
var days = new Dictionary<int, Day>()
days[1] = day1;
...
days[8] = day8;
//Simplfiy your method
private void btnCandlesLight_Click(object sender, EventArgs e)
{
try
{
var dayIndex = Convert.ToInt32(textBox1.Text);
if(dayIndex > 0 && dayIndex <= 8)
{
days[dayIndex].Start(); //Get the corresponding day via its Key
LightUpCandles(dayIndex); //pass the key as a parameter
}
else
{
MessageBox.Show("Enter new day");
}
}
catch(InvalidCastException exception)
{
//Whatever you do when the textbox cannot be parsed
}
}
I still don't get what your candlesOne to five methods are really doing or why the method "candlesOne" lights up two candles (pay attention to the variable naming). I also don't get how this makes up some kind of timer... but here's a first potential refactoring for it anyway:
public void LightUpCandles(int dayIndex)
{
firedmatch.Left = firedmatch.Left + 100;
if(c == 1)
{
candle1.Visible = true;
}
if(c == 3 && dayIndex > 1)
{
candle2.Visible = true;
}
if(c == 5 && dayIndex > 2)
{
candle3.Visible = true;
}
if(c == 7 && dayIndex > 3)
{
candle4.Visible = true;
}
if(c == 11 && dayIndex > 4)
{
candle5.Visible = true;
}
}
Your switch logic is correct which I tested with the following;
int result;
result = Convert.ToInt32(textBox1.Text);
switch (result)
{
case 1:
MessageBox.Show("1");
break;
case 2:
MessageBox.Show("2");
break;
case 3:
MessageBox.Show("3");
break;
case 4:
MessageBox.Show("4");
break;
case 5:
MessageBox.Show("5");
break;
case 6:
MessageBox.Show("6");
break;
case 7:
MessageBox.Show("7");
break;
case 8:
MessageBox.Show("8");
break;
default:
MessageBox.Show("Enter new day");
break;
}
If you don't get the same results I would perhaps look at making the message boxes above display the data type of the variable.
MessageBox.Show(result.GetType().ToString());

How can I declare string reference variable in C#?

The best way to illustrate my question is this C# example:
//It seems that the comment is required:
//I need to change the values of someString0, someString1, or someStringN
//depending on the `type` variable
ref string strKey;
switch(type)
{
case 0:
strKey = ref someString0;
break;
case 1:
strKey = ref someString1;
break;
//And so on
default:
strKey = ref someStringN;
break;
}
//Set string
strKey = "New Value";
Can I do this in C#?
PS. I know that I can do this in a function. I'm asking about an "in-line" approach.
If you really want to do the assignment similar to the way you're asking for, here is one way that doesn't use ref
Action<string> action;
switch (type) {
case 0:
action = newVal => someString0 = newVal;
break;
case 1:
action = newVal => someString1 = newVal;
break;
case 2:
action = newVal => someString2 = newVal;
break;
default:
action = null;
break;
}
if (action != null) action.Invoke("some new value");
Performance-wise, the above takes about 8 nanoseconds longer to execute than the direct alternative below
switch (i) {
case 0:
someString0 = "some new value";
break;
case 1:
someString1 = "some new value";
break;
case 2:
someString2 = "some new value";
break;
default:
break;
}
But you're talking a little longer than next to nothing. On my not particularly fast laptop, the Action version takes around 13 nanoseconds to execute vs. the direct assignment method that takes around 5.5 nanoseconds. Neither is likely to be a bottleneck that matters.
why are you splitting this up into a switch and then an assignment later? why not just set the value in the switch and avoid the ref behavior at all?
string newValue = "new value";
switch(type)
{
case 0:
someString0 = newValue;
break;
case 1:
someString1 = newValue;
break;
//And so on
default:
someStringN = newValue;
break;
}
Why don't you just set the correct string variable like this:
switch(type)
{
case 0:
someString0 = "New Value";
break;
case 1:
someString1 = "New Value";
break;
//And so on
default:
someStringN = "New Value";
break;
}
An even better approach is to replace your n string variables with an array of strings so that the assignment becomes a single line of code:
string[] someString;
someString[type] = "New Value";

C# Switches vs. VB Case Statements

I recently switched from VB to C#. One thing that I noticed was that in C#, I have problems using comparisons as part of the case. I am not sure how to explain it in words, so here is an example of what I am trying to do.
In VB, my code looks like this and works perfectly fine.
Select Case ExamScore
Case Is >= 90
Grade = "A"
Case Is >= 80
Grade = "B"
Case Is >= 70
Grade = "C"
Case Is >= 60
Grade = "D"
Case Else
Grade = "F"
End Select
In C# on the other hand, Visual Studio tells me that ">=" is an invalid expression.
switch (examScore)
{
case >= 90: grade = "A"; break;
case >= 80: grade = "B"; break;
case >= 70: grade = "C"; break;
case >= 60; grade = "D"; break;
default: grade = "F"; break;
}
Am I doing something wrong here, or is it simply not possible to do this in C#?
Thank you very much in advance!
Top part of this answer is true for C# versions before 7. See below the line for an update for version 7
It's not possible. C# switches can only switch on exact equality:
Each case label specifies a constant value. Control is transferred to the switch section whose case label contains a constant value that matches the value of the switch expression,
You could replace it with a stack of if/else statements, or if you prefer, you can make something that looks quite compact, but some may frown on - a nest of conditional operators:
grade = examScore >= 90 ? "A" :
examScore >= 80 ? "B" :
examScore >= 70 ? "C" :
examScore >= 60 ? "D" :
"F";
With C# 7, switch has been significantly enhanced, and it's now possible to apply more conditions within cases, although it's still not as "clean" as the VB version. E.g. you could do something like:
switch (examScore)
{
case int es when es >= 90: grade = "A"; break;
case int es when es >= 80: grade = "B"; break;
case int es when es >= 70: grade = "C"; break;
case int es when es >= 60; grade = "D"; break;
default: grade = "F"; break;
}
Assuming that examScore is an int, this somewhat abuses the new "pattern matching on types" facility to be able to have something to say in the case clause, and then using the when clauses to apply arbitrary conditions to the newly introduced variable.
Unlike in VB, the C# switch statement is something like "equals" check. So you might need a if else ladder in order to accomplish this.
You may try something like:
private char Grade(int marks)
{
Dictionary<int, char> grades = new Dictionary<int, char> { { 60, 'A' }, { 50, 'B' } };
foreach (var item in grades)
{
if (marks > item.Key)
return item.Value;
}
return 'C';
}
It's not possible in C#.
Use a bunch of ifs instead.
You can have it all in nice function:
public string Grade(int examScore)
{
if(examScore>=90)
{
return "A";
}
if(examScore>=80)
{
return "B";
}
if(examScore>=70)
{
return "C";
}
if(examScore>=60)
{
return "D";
}
return "F";
}
If you really want a switch statement you could use integer division
int i = 69;
switch (Math.Min(9, i / 10))
{
case 9: Grade = "A"; break;
case 6: Grade = "B"; break;
}

Categories