Can I use a variable in a switch statement? - c#

I am coding a text based adventure, and am having a problem. I am trying to make a switch statement case that handles every examination action you want, and am getting this for my code so far:
case "examine" + string x:
//this is a method that I made that makes sure that it is an object in the area
bool iseobj = tut.Check(x);
if (iseobj)
x.examine();
else
Console.WriteLine("That isn't an object to examine");
break;
How do I use a variable in my case statement? I want any string starting with "examine" + (x) to trigger the case.

Your scenario would fit into an if-else statement better than a switch statement. In C#, a switch can only evaluate values, not expressions. This means you can't do:
case input.StartsWith("examine"):
However, you can make this work with an if statement! Consider doing the following:
if (input.StartsWith("examine"))
{
//this is a method that I made that makes sure that it is an object in the area
bool iseobj = tut.Check(x);
if (iseobj)
x.examine();
else
Console.WriteLine("That isn't an object to examine");
}
else if (...) // other branches here

Related

c# Using enum in Switch Case throwing exception

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")

How to use a variable into a "case" of a switch case

I'm a beginner in C# and I'm developing an HMI (WinForms).
I have a DataGridView filled with data and some column with buttons.
When I click on a button of the column, the CellContentClick event is triggering and I would like to get the precise column where the user clicked, using a switch case:
(simplified code)
private void dataGridView1_CellContentClick(object sender, DataGridViewCellEventArgs e)
{
var senderGrid = (DataGridView)sender;
if (senderGrid.Columns[e.ColumnIndex] is DataGridViewButtonColumn && e.RowIndex >= 0) // if cell button
{
switch (e.ColumnIndex)
{
case Column1.Index: // <- not building because Column1.Index is a variable
// do something
break;
case Column2.Index:
// do something
break;
//etc
default: break;
}
}
}
The problem is that ColumnX.Index can not be put into the case condition because it's a variable. Of course, I could use directly the number of the column index, but since I'm developing and always moving the columns, I would like to keep the ColumnX.Index way.
Switches cannot have dynamic evaluated statements in the case statement. They must be statically evaluated.
Below post explain it why :
C# switch statement limitations - why?
Also you can use alternative ways, as explained in below link:
Is there a better alternative than this to 'switch on type'?
Depending on what you need in your particular case, you could also make use of "Tag" property of the column (it's on DataGridViewBand that is base for DataGridViewColumn). When I worked with forms I used to place there operation code that the button is supposed to trigger.
So on the column you place for example Tag="UpdateRecord" and in the code you can have
switch (column.Tag as string)
{
case "UpdateRecord":
// Update code
break;
// Other cases
}
This way you can easily reorder columns of your grid without playing with fixing those switches.
Also (as the next step towards cleaner code) you could put "UpdateRecord" text into const in some class and use it in column definition and switch definition.
You'll need to use something else - an else or else if statement could work for you. You could also use an enum of the expected value and reference them in your case statement.
I'd like to keep the switch case method
Well, you can abuse pattern matching:
switch (c.ColumnIndex)
{
case int i when i == Column1.Index:
// do something
break;
case int i when i == Column2.Index:
// do something
break;
//etc
default: break;
}
but I would not recommend.

Switch Statement with Enum - Or (||) and (&&)

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.

Spooky scoping issues - C# - Switch - Case [duplicate]

This question already has answers here:
Variable declaration in a C# switch statement [duplicate]
(7 answers)
odd variable scope in switch statement
(4 answers)
Closed 9 years ago.
So if I have a switch with 3 cases, each case has duplicate local variables declared in them. You would think that the variables would be local to that case so you should be able to use the same name repeatedly. However, this doesn't appear to be the 'case'.
Apparently the other case blocks can see the variables in each other.
Okay, no big deal right? Except that when you try and access that variable that it can obviously see, it says it can't see it???
int index = list.SelectedIndex;
switch(index){
case(0):
bool val = true; //First declaration s'allll good
if(val) //No issues here either obviously
MessageBox.Show("Huh?");
break;
case(1):
bool val = true; //Says it already exists??
if(val)
MessageBox.Show("Huh?");
break;
case(2):
bool val3 = true; //Change the variable name so you can use it however,
if(val) //When you try to access the val in case 0 it says it doesn't exist?????
MessageBox.Show("Huh?");
break;
}
Is there an obvious syntax fold in space time I am missing here?
The variables, in the IL, are defined to the scope of the switch, so you can't reuse them in the other case statements because it would redefine them.
Likewise, you still have to define the variables for each case (i.e. you've seen how even if one case has the variable the others can't actually leverage its definition).
The better approach, for you, is to define val outside the switch.
Since cases are just labels, there's no scoping between cases -- they can see variables on the highest scope of the case, hence collisions on your val.
You can either move bool val outside of the switch, or you can enclose the cases in braces to scope it yourself, i.e.
case(0):
{
bool val = true;
if (val)
MessageBox.Show("Huh?");
}
break;
Variables in a switch statement are scoped to the entire switch statement. See this MSDN page at the bottom "The scope of a local variable or constant declared in a switch block is the switch block.".
To get around this, you can either declare the variable above the switch statement or (less cleanly) declare it a single time and re-use throughout the switch statement like so.
int index = list.SelectedIndex;
switch(index){
case(0):
bool val = true; //First declaration s'allll good
if(val) //No issues here either obviously
MessageBox.Show("Huh?");
break;
case(1):
val = true; //Declared in case 0
if(val)
MessageBox.Show("Huh?");
break;
case(2):
val = true; //Still declared from case 0
if(val)
MessageBox.Show("Huh?");
break;
}

C# variable scopes and the "switch" statement?

This kind of code would normally work in PHP, but since the scope is much more strict in C#, it's not. I can't figure out a way to write this code without repeating myself.
static double Cube()
{
Console.Write("Enter the side length of the cube: ");
try
{
double x = Convert.ToDouble(Console.Read());
return Math.Pow(x, 3);
}
catch (FormatException)
{
Console.WriteLine("Invalid input, please enter a number.");
Cube();
}
return 1;
}
..Later in Main():
switch (choice)
{
case 0:
return;
case 1:
double final = Cube();
break;
default:
Console.WriteLine("Please enter 0 or 1.");
Main();
break;
}
Console.WriteLine("The volume is: {0}", Convert.ToString(final));
The Cube() method works fine, but it's messy in my opinion (return 1 at the end to make the compiler happy). But an error comes up saying The name 'final' does not exist in the current context. It can't find final. So the only way to make this work that I'm seeing is to put the Console.WriteLine statement right after the double final = Cube().
I've also tried declaring double final; outside the switch, then just setting final inside each case, but that hasn't worked either.
Thanks!
You're right: this is a mess. Start over.
Your fundamental problem is that you're not separating your concerns. You have a method that does user input, input validation, retry logic and math all at the same time. You should rather make methods for each.
Also, use TryParse to handle the failure case, not exception handling.
Finally, recursion is completely the wrong tool to use. A problem must have the following characteristics to be solved by recursion:
A trivial base case.
Can be reduced to a set of smaller problems.
Solutions to smaller problems can be combined to solve larger problems.
Making a problem smaller repeatedly eventually gets to the trivial case.
Your problem has none of these properties, so recursion is automatically the wrong tool. The tool you want is a loop.
static void Main()
{
double x = ObtainDoubleFromUser(
"Enter the side length of the cube: ",
"Please enter a number: ");
Console.WriteLine("The volume is {0}", Cube(x));
}
static double ObtainDoubleFromUser(string firstMessage, string failureMessage)
{
Console.Write(firstMessage);
while(true)
{
double result;
if (Double.TryParse(Console.Read(), out result))
return result;
Console.Write(failureMessage);
}
}
static double Cube(double x)
{
return Math.Pow(x, 3);
}
Does that all make sense? You want to avoid recursion and exception handling if you possibly can. And keep your concerns separated.
If you want to access final from outside the switch scope, you'll have to declare it outside that scope too. If you reference final and there are code paths that allow not setting a value to final, then the compiler will be "angry".
In php, final would magically be 0 when you don't assign anything to it. Try declaring final before the switch, and then assign a value to it at each case statement including the default case.
Place the variable declaration before your switch statement:
double final = 0.0;
switch(choice)
{
...
}
Then just use the variable in your switch statement:
case 1:
final = Cube();
break;
In C#, variables must be declared before they can be used. In your code, the declaration was limited to the scope of the switch statement. Declaring the variable prior to the switch statement ensures that its in the scope of the method, allowing it to be used inside and after the switch statement.

Categories