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;
}
Related
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
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 3 years ago.
Improve this question
Let's make it easier. In this case return at the end have squigglies. What should I type in the return at the end to receive VK_F2 as a return value from the method?
internal uint AssignStartShortcut()
{
switch (currentStartValue)
{
case "F2":
return VK_F2;
}
return;// how this should look?
}
If I don't use return after swith then I have message: not all code paths return value.
Your error most likely is:
Compiler Error CS0165
Use of unassigned local variable 'name'
The C# compiler does not allow the use of uninitialized variables. If
the compiler detects the use of a variable that might not have been
initialized, it generates compiler error CS0165. For more information,
see Fields. Note that this error is generated when the compiler
encounters a construct that might result in the use of an unassigned
variable, even if your particular code does not. This avoids the
necessity of overly-complex rules for definite assignment.
Easy fix, initialize it:
internal uint AssignStopShortcut()
{
uint stopNumber = 0;
switch (currentStartValue)
...
Or make sure the static analyser knows that it can't fall through (i.e it is always initialized)
uint stopNumber;
switch (currentStartValue)
{
case "F3":
stopNumber = VK_F3;
return stopNumber; //squigly lines below
default:
// no other options
throw new InvalidOperationException("Bazzinga!");
}
Or even better, just return the constant, don't use the local variable.
internal uint AssignStopShortcut()
{
switch (currentStartValue)
{
case "F3":
return VK_F3; //squigly lines below
default:
throw new InvalidOperationException("Bazzinga!");
}
}
Adding to the TheGeneral's solution, your problem is that you need to initialise the variable.
internal uint AssignStartShortcut()
{
uint startNumber = 0; //initialise variable
if (currentStartValue == "F2")
{
startNumber = VK_F2;
}
return startNumber; //value of 0 is returned if the IF statement conditon is not met.
}
From your comment to TheGenral's proposed solution as I cannot yet make comments, is that since the initialised variable is set to Zero in this case and you are only doing a check for a particular value and if that condition is not met then "startNumber" won't be updated with "VK_F2" or "VK_F3" values. Therefore, that's why the Switch statement default case is met as the "currentStartValue" had not met any of the cases.
For example if you wanted to check for all cases, it should look something like this:
internal uint AssignStopShortcut()
{
uint stopNumber = 0; //initialise this variable is a must if it's to be declared in this method.
switch (currentStartValue)
{
case "F1": break;
case "F2": break;
case "F3":
stopNumber = VK_F3;
break;
case "F4": break;
case "F5": break;
case "F6": break;
case "F7": break;
case "F8": break;
default:
// no other options
throw new InvalidOperationException("Bazzinga!");
}
return stopNumber;
}
Hope this helps.
Thanks to all of you guys for your help. Problem solved and it wasn't in if or switch statement. Turns out data that should be passed simply wasn't. My bad. Thanks again.
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
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.
How can I refactor a switch statement that is in multiple places in code that assigns a value to a variable depending on which case is thrown, for example:
int a = 0;
int b = 0;
switch(c)
{
case "1"
a = 1;
break;
case "2"
b = 2;
break;
}
In the above example, resharper will use one of the variables as the return and the other as an out parameter. Is there another way to do it, maybe not extracting out the whole switch block.
This code block has a couple of different ways of refactoring it to make it more reusable without having it copied over in places. However, they're going to require reworks of things:
Are the objects logically grouped somehow?
If so, then you could make an object to represent them, and then refactor to return the object set with values.
var myObj = SetObjectAccordingTo(c);
protected SomeObj SetObjectAccordingTo(string c)
{
var myObj = new SomeObj();
switch(c)
{
case "1": myObj.a = 1;
break;
case "2": myObj.b = 2;
break;
}
return myObj;
}
If they are not logically grouped, and each is assigned a value...
Then logic for determining each value needs to be split.
a = DetermineValueForA(c);
b = DetermineValueForB(c);
And each method deals only with the cases where a is involved.
If they are not logically grouped, and only certain values are assigned...
Then there is not much optimization that can be performed save moving the respective values to member variables and then calling each with that specific method.
If you could provide a sample of what you're trying to do, we could offer a solution more than likely.
You mean you'd like to extract this as a method? You might consider returning a struct (or perhaps a class) if A and B are related in some manner. Perhaps, NDA permitting, you could show us a code fragment in context so it might become clearer how to solve this.