Having a problem using switches in C# - c#

I'm getting the error "A switch expression or case label must be a bool, char, string, integral, enum, or corresponding nullable type" in my code at the line,
switch (job_selecter.SelectedValue)
Here's my code:
private void start()
{
switch (job_selecter.SelectedValue)
{
case 0:
head_seal_label.Text = "Ravager's Seal: Head (8)";
break;
}
}
Could anyone tell me why this is happening and how I can fix it? Thanks!

job_selecter.SelectedValue is probably an object.
private void start()
{
int index = (int)job_selecter.SelectedValue;
switch (index )
{
case 0:
head_seal_label.Text = "Ravager's Seal: Head (8)";
break;
}
}

It seems like what you really want to do is this:
switch(job_selecter.SelectedIndex)
{
case 0:
// do whatever
break;
default:
// handle default case
break;
}
You've noted in one of your responses that casting SelectedValue to string or int or whatever can cause a null reference exception if you then use it in a switch--which makes perfect sense, because it's perfectly legal for a combo box to have nothing selected, and you're going to need to account for that case. If you switch on SelectedIndex, handling -1 will allow you to handle a case of "no selection" specifically.
Of course, it's worth pointing out that switching on SelectedIndex only makes sense if the combo box contains a known, unchanging set of values. Adding or removing values will potentially cause the indices of everything in the box to change, thus breaking the switch.

SelectedValue is an object. cast it to an int in the switch.

You might have meant to use "SelectedIndex" property (a zero based number corresponding to your selection in combo OR a -1 when nothing is selected):
switch (job_selecter.SelectedIndex)
{
case 0:
head_seal_label.Text = "Ravager's Seal: Head (8)";
break;
// other cases for other Indices
case -1:
default:
// handle nothing selected...
}

You should get your SelectedIndex into an int first, to deal with this error " "A switch expression or case label must be a bool, char, string, integral, enum, or corresponding nullable type" in my code at the line":
int index;
if(!Int32.TryParse(job_selector.SelectedIndex.ToString(), out index))
{
index = -1;
}
//All your other cases here
switch(index)
{
case 0:
head_seal_label.Text = "Ravager's Seal: Head (8)";
break;
default:
head_seal_label.Text = "Some default Value";
break;
}

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.

How do I return an item when the type is read from file

I am calling a function that has a type declared against the method, ie.
public T Get<T>().
I read in a string from a file and parse this through a switch to determine the type used, ie.
switch (type)
{
case "Text":
item = Get<Text>();
break;
case "Button":
item = Get<Button>();
break;
}
How would I then go about returning the item of Type from the function where it was called? Note that I don't want to return a common parent as I need access to the methods of the derived class.
public <????> newGet()
{
switch (type)
{
case "Text":
item = Get<Text>();
break;
case "Button":
item = Get<Button>();
break;
}
return item;
}
Using dynamic sounds like a bad idea. You should reconsider what you're doing here.
"Note that I don't want to return a common parent as I need access to the methods of the derived class."
OK, so... you're going to do what to access these methods? Use another switch to switch between the types and then call the methods you want? Why are there two switch statements here doing the same thing? I don't know the exact architecture of what you're dealing with, but generally you'd be better off finding out what type you're going to be getting back (i.e. by returning "Text" or "Button" or whatever from a function) and then calling a strongly-typed function which goes and gets the thing and calls methods on it.
You can consider using the dynamic type. It's only available for .NET 4.0 and above
public dynamic newGet(string type)
{
dynamic item = null;
switch (type)
{
case "Text":
item = "ABC";
break;
case "Number":
item = 1;
break;
}
return item;
}
As you can see, I can use the Length of the string returned from newGet
dynamic text= newGet("Text");
Console.WriteLine(text.Length); //"ABC".Length = 3
dynamic number= newGet("Number");
Console.WriteLine(number + 5); //1 + 5 = 6
This can also works. Just be careful of runtime exception
string text= newGet("Text"); //You can assign to
Console.WriteLine(text.Length); //"ABC".Length = 3
int number= newGet("Number");
Console.WriteLine(number + 5); //1 + 5 = 6

ArgumentOutOfRange Exception thrown

I have been writing a Winforms application, in which the user selects something from a comboBox. However, when I run the application, the compiler throws an ArgumentOutOfRange Exception because the index was -1.
Code:
if (comboBox1.Enabled == false || comboBox2.Enabled == true || comboBox3.Enabled == false)
{
int index = comboBox2.SelectedIndex;
string t = comboBox2.Items[index].ToString();//<==EXCEPTION
switch (t)
{
case "Ounzes==>Pounds":
break;
case "Pounds==>Ounzes":
break;
case "Tons==>Pounds":
break;
case "Pounds==>Tons":
break;
case "Ounzes==>Tons":
break;
case "Tons==>Ounzes":
break;
case "Stone==>Pound":
break;
case "Pound==>Stone":
break;
case "Tons==>Stone":
break;
case "Stone==>Ton":
break;
}
}
Can anyone please explain why this exception is being thrown, because I did select something from the comboBox.
It appears that no item was selected in your ComboBox. Take a look at the documentation:
A zero-based index of the currently selected item. A value of negative one (-1) is returned if no item is selected.
The most obvious way to fix this is just to check to make sure an item has been selected before you try to use it, like this:
int index = comboBox2.SelectedIndex;
if (index >= 0)
{
string t = comboBox2.Items[index].ToString();
switch (t)
{
...
}
}
Check when your code is firing. Might be when combo1 is being populated, but combo2 hasn't yet.
As others have said quick way is to test selectedIndex >= 0 or selectItem != null.
The best thing to do would be,put the code in a try catch block and you'll find out answers for yourself :)

Preventing If within If functions (or cases)

I'm building a code where I have to go trough alot of if/case functions. This on itself is not really a problem only that alot of these if's are the kinda the same.
In my code it has to go trough an if function, and if there is a match it wont matter what match it is it will have to go trough the same next if. But depending on both answers it will have to go to a different part of the code.
So for exmaple:
Switch(A){
case 1:
Switch(B){
case 1: do11thing();
case 2: do12thing();
}
case 2:
Switch(B){
case 1: do21thing();
case 2: do22thing();
}
}
Does anyone know a solution instead of having to place the Switch(B) a lot of times within my code.
In case you have more jumps than executable code (the case that happens quite often when programming state machines), you may store your logic in some nested Dictionary, List and/or array object like the following:
// Maps A and B values to functionality
var funcs = new[] {
new[] { func00, func01, func02, ... },
new[] { func10, func11, func12, ... },
new[] { func20, func21, func22, ... },
...
};
// Actually runs functionality according to your mapping
funcs[A][B](params);
So, in case of A=1 and B=2, the func12 will be called.
Of course, you may use lambdas (params) => {} as funcs in the structure.
you can use one if for the function returning value 2 , and then inside this if use all possibilities as different switch cases.It will be smoother and faster than multiple if loops.
for ex :-
if (2 == function1) {
switch(value of function 2)
{
case value_1:
..//do whatever u want;
break;
case value_2:
..//do whatever u want;
break;
default:
//do some error handling;
break;
}
}
One thing you can do is combine cases. For example, say you have a string value that's your outer switch variable, and an int that's the inner switch variable. Your original code might be:
switch (theString)
{
case "Foo":
switch (theInt)
{
case 1: DoThing1(); break;
case 2: DoThing2(); break;
// many other cases
}
DoFooThing();
break;
case "Bar":
switch (theInt)
{
case 1: DoThing1(); break;
case 2: DoThing2(); break;
// other cases, same as with "Foo"
}
DoBarThing();
break;
}
You can combine the cases and have a conditional:
switch (theString)
{
case "Foo":
case "Bar":
switch (theInt)
{
case 1: DoThing1(); break;
case 2: DoThing2(); break;
// many other cases
}
if (theString == "Foo")
DoFooThing();
else
DoBarThing();
break;
}
The type of logic you're describing, especially if there are very many cases, is probably best implemented using a lookup table. Doing so makes it much easier to follow the logic. It takes a bit more time to set up, but you can easily see in the table that you construct exactly what will happen with any combination of input values.

Categories