any way to use variables in c# switch case? - c#

I know that case cannot work with non-constant values, but what should I do if its impossible to make a constant? thats my case: we have three variables, need to find that, one that will correspond to the value of the switch condition, but how to do this if the case is not able to work with non-constants? are there any workarounds?
float value = 4;
float number1 = 3, number2 = 6, number3 = 4;
switch (value)
{
case number1:
{
break;
}
case number2:
{
break;
}
case number3:
{
break;
}
}
here is the oversimplified example, and yes, you can easily do this using if/else if, but what if the number of values will be 100? what to do in that case?

One approach is to use an inverted Dictionary, where the key is the value and the value the key. Something like this:
var d = new Dictionary<int, int>();
d.Add(3, 1);
d.Add(6, 2);
d.Add(4, 3);
int keyPtr = d[value];
switch (keyPtr):
{
case 1:
//do something.
break;
case 2:
//do something else.
break;
case 3:
//do something different.
break;
}
Obviously this is simplified, and I have used int not float, but the same applies to any type. Using this technique,
your n variables, become the first n items in the Dictionary. In practice at the very least, you should check if your given value exists as a key in the Dictionary. It should help you in the right direction.

If you simply want to check whether your value variable equals to at least one of the variables number1, number2, number3, you could create an array of those numbers, say numbers[] and then create a method such as:
private bool checkValue(float value, float[] numbers) {
foreach (float num in numbers) {
if (num == value) return true;
}
return false;
}
This solution fits any number of elements in your numbers array.
If you want you can also use a List<float> instead of an array, so you could dynamically add more and more elements (Without a fixed size).

Related

Defining a variable inside a switch() closure

Is it possible in C# to define a variable like so?
switch(var num = getSomeNum()) {
case 1: //Do something with num
break;
default: break;
}
public static int GetSomeNum() => 3;
The documentation says that
In C# 6, the match expression must be an expression that returns a
value of the following types:
a char.
a string.
a bool.
an integral value, such as an int or a long.
an enum value.
Starting with C# 7, the match expression can be any non-null
expression.
To answer your question,
Yes you can switch on an int, e.g.
int myInt = 3;
switch(myInt)
Yes you can switch on the result of a method that returns an it, e.g.
int GetMyInt()
{
// Get my Int
}
switch(GetMyInt())
Yes you can switch on variable populated with a method result, e.g.
int GetMyInt()
{
// Get my Int
}
int myInt = GetMyInt();
switch(myInt)
No you can't do it like that.

Assign a formula at runtime for accessing elements of List

The scenario is that I have say two different types of cases - case 1 and case 2. For case 1 and case 2 each I have a certain startIndex, endIndex and a formula for accessing the elements of a List.
Now for assigning values startIndex and endIndex I am preferring a normal switch case, however I am at loss for the formula for accessing elements. For case 1 it is say something like List[ a+i ] and for case 2 it is say List[a + (i-b)].
One way can be to have a for loop like this
for(int i=0;;i++)
{
if(case is 1)
then f=a+i
else if(case 2)
then f=a+(i-b)
}
I thought of using delegates. however, as per my knowledge they need to be made global. Actions do not return value. Func can be used but one expression/formula takes only one element (int) and the other takes 3. I need something in lines to this like that anonymous function can be assigned any of above mentioned formulae at runtime from the switch case (as the cases might and will increase in future).
Thank you.
I thought of using delegates. however, as per my knowledge they need
to be made global.
This is not true (actually, there are no truly global variables in C#, since each and every variable needs to be encapsulated inside an object). A public delegate type is indeed visible to all code after referencing the assembly containing this type's code, but a variable of such type can be private.
What I recommend in your situation is to have some sort of mapping from case numbers to delegates. A good idea is to use a Dictionary<TKey, TValue> if you have at most one delegate per case. This dictionary can be stored as a private variable inside the class where your method resides.
public class MyClass
{
private Dictionary<int, Delegate> _delegateMapping = new Dictionary<int, Delegate>;
}
There are a couple of ways you can add elements do the dictionary in the constructor: passing the already populated dictionary, passing an array of delegates, creating these delegates in the constructor itself. Either way, you'll end up with a dictionary of Delegate types, so you'll need to use a cast to be able to use them in your code properly.
for (int i = 1; i < _delegateMapping.Count; i++)
{
switch (i)
{
case 1:
var f = (Action<int>)_delegateMapping[1];
f(i);
break;
case 2:
var f = (Action<int, int>)_delegateMapping[2];
f(i, a);
break;
}
}
Of course I'm greatly improvising here.
It is important to note that if the type of delegate changes inside the dictionary, you will have to modify the cast accordingly inside the switch statement. Otherwise, if no implicit cast exists, you'll get a runtime exception.
Hi guys thank you so very much for your feedbacks. I finally found the solution with Func. This is what my code looks like. I had to manipulate the Func usage a little. I made almost all the vars which I have to use in the Func as global/local to the function where I write these Funcs. My apologies, if I was not able to explain my problem properly.
int i = -1;
Func<int,int> formula = null;
switch(f)
{
case 1:
{
formula = new Func<int,int>(index => { return i; });
}
break;
case 2:
{
formula = new Func<int, int>( index => { return s- (i * c); } );//here s and c are global variables.
}
break;
}
i = startIndex;
while(i < endIndex)
{
var Obj= List[formula.Invoke(i)];
//my code goes here
i++;
}
Let me know if my solution is correct w.r.t performance, logic, C# programming, etc.. :)
EDITED::
#usr and #Kapol I tried the way you suggested and tried to improvise the code like this.
private Dictionary<int, Func<int[], int>> indexFormulae;
private void assignDelegates()
{
indexFormulae = new Dictionary<int, Func<int[], int>>();
indexFormulae.Add(0, getFormula_1);
indexFormulae.Add(1, getFormula_2);
}
private void someFunction(int sp)
{
int i = 0;
Func<int[], int> formula = null;
indexFormulae.TryGetValue(formation,out formula);
i = startIndex;
while (i < endIndex)
{
int[] intValues = new int[] {i,sp,globalVar };
var Obj = List[formula.Invoke(intValues)];
//My code here
i++;
}
}
private int getFormula_1(params int[] intValues)
{
return intValues[0];
}
private int getIndex_Vertical(params int[] intValues)
{
return intValues[1] - (intValues[0] * intValues[2]);
}
So, that with this now I can use these two getFormula methods anywhere in this class rather than keeping them anonymous. and also I think I will stick to params because I might have N number of int params in future for other functions.

how do i use an array in a switch statement in c#?

So i am new to programming so im pretty confused about this. I created an array and tried to use it inside of a switch statement:
string[] General = new string[5];
{
General[0] = "help";
General[1] = "commands";
General[2] = "hello";
General[3] = "info";
General[4] = "quit";
}
switch(General)
{
case 0:
{
Console.ForegroundColor = ConsoleColor.Blue;
Console.WriteLine("This is a new program. Therefore the amount of commands are limited. \nIt can do simple things. For example, if you say 'tell the time' then it will tell the time\n");
Console.ForegroundColor = oldColor;
continue;
}
}
As far as i am aware there are no problems with this. However, when i run the code i am greeted with this error : "A switch expression or case label must be a bool, char, string, integral, enum, or corresponding nullable type"
I am genuinely stuck with this and i cant find any answers on the internet so any help will be greatly appreciated. Thanks
It sounds like what you are looking for is an enum.
public enum General {
help = 0,
commands = 1,
hello = 2,
info = 3,
quit = 4
}
Then you can use a switch statement just fine :).
// variable to switch
General myGeneral;
// myGeneral is set to something
switch(myGeneral)
{
case General.help:
Console.ForegroundColor = ConsoleColor.Blue;
Console.WriteLine("This is a new program. Therefore the amount of commands are limited. \nIt can do simple things. For example, if you say 'tell the time' then it will tell the time\n");
Console.ForegroundColor = oldColor;
break;
}
You are doing the switch statement on the entire array, opposed to a single entry in the array.
Assuming you are trying to write all of the available inputs you could do
string[] General = new string[5];
{
General[0] = "help";
General[1] = "commands";
General[2] = "hello";
General[3] = "info";
General[4] = "quit";
}
foreach(var option in General)
{
switch(option)
{
case "help":
{
Console.ForegroundColor = ConsoleColor.Blue;
Console.WriteLine("This is a new program. Therefore the amount of commands are limited. \nIt can do simple things. For example, if you say 'tell the time' then it will tell the time\n");
Console.ForegroundColor = oldColor;
break;
}
case "commands":
{
//Do some stuff
break;
}
//etc etc
}
}
The parameter in the switch statement should be the user input, not your optional values, for example:
int input = 0; // get the user input somehow
switch (input)
{
case 0:
{
// Do stuff, and remember to return or break
}
// Other cases
}
Also, this is a perfect use case for an Enum. That would look something like this:
public enum General
{
HELP = 0,
COMMANDS = 1,
HELLO = 2,
INFO = 3,
QUIT = 4
}
int input = 0; // get the user input somehow
switch (input)
{
case General.HELP: //Notice the difference?
{
// Do stuff, and remember to return or break
}
// Other cases
}
This makes your intention very clear, and therefore makes your code more readable and more maintainable. You can't do this with your array, because even though you declare your array in your code, it is still variable and therefore its state at the switch statement is not known at compile time. Enums are immutable, and therefore their values are known at compile time and can be used in switch statements.

switch case from a list of integers ,code optimization

i have a large switch case ,and i also have a list of integers say{1610616833,1610747905,1610878977,1610878977,1611010049}
i want to do the following
int a;
switch (incomingint)
{
case 1:
//some code
break;
case 2:
//some code
breakl
//now i want to check if this one is one of the list's integers or not
//so i did the following
case 1610616833:
a=0;
break;
case 1610747905:
a=1;
break;
case 1610878977:
a=2;
break;
}
The problem is :
I have around 16 element in the list
The code in the case of one of the list's members is almost the same except in the value i set for a .
NOTE:
setting the value of 'a' occurs only when the incomingint is one of the list members
so instead of writing all of that code, is there any way to optimize this code??
You could use a dictionary for this transformation:
Dictionary<int, int> transformation = new Dictionary<int, int>
{
{ 1000, 0 },
{ 1001, 1 },
// etc
};
int a = 0; // Default value
if (transformation.TryGetValue(incomingint, out a))
{
// a has the value. If you need to do something else, you might do it here because you know that dictionary had incomingint
}
You can create a dictionary that will be a mapping between your list items and values of a.
var dict = new Dictionary<int,int>();
dict.Add(1000, 0);
dict.Add(1001, 1);
dict.Add(1002, 5);
...
And later:
a = dict[incomingint];
If there is a direct way to compute a from incomingint, just use incomingint in the calculation. The data you posted looks like you could simply do:
a = incomingint - 1000;
For incomingint of values 1000 and above.
it seems like you can optimize this by writing
if (incomingint > 1000) a = incomingint - 1000;
in other news, if you have 16 ints in a list, you almost definitely don't need to optimize it. that's a tiny, blazing-fast amount of work.

"a constant value is expected" error in switch statement in c#

switch (Rotation.ToString())
{
case (-Math.PI / 2).ToString():
// some code
break;
}
The compiler complains about (-Math.PI / 2).ToString(), "a constant value is expected"
Isn't that a constant?
No method call is a constant value.
Incidentally, since Math.PI is a double, you might want to not use it in "equality" comparisons as you are doing here; there are well-documented pitfalls.
A better approach for a single test would be:
var target = -Math.PI / 2;
if (Math.Abs(Rotation - target) < 0.0001) {
// some code
}
If there are lots of branches, without going into delegate territory, you can do something like this:
var specialCases = new[] { -Math.PI, -Math.PI / 2 };
var epsilon = 0.001d;
var index = specialCases.Select((d, i) => Math.Abs(Rotation - d) < epsilon ? i : -1)
.Where(i => i != -1).DefaultIfEmpty(-1).First();
switch (index) {
case 0: // -Math.PI
break;
case 1: // -Math.PI / 2
break;
default: // No match
break;
}
Not the best use of LINQ, but it will allow you to get back to switch territory with a minimum of tinkering.
Jon answers the gist of the question: the result of a method call is never considered to be a constant from the compiler's perspective. You can do this:
string i = (-Math.PI / 2).ToString();
switch(i)
{
case "-1.5707963267949": Console.WriteLine("hi");
break;
}
However, bear in mind that double.ToString() may produce different results depending on the current culture info. (Hence the reason it cannot be constant.) So you're probably better off using the double value directly and, depending on the size of your switch statement, either creating a few if/else statements, or creating a Dictionary keyed on the constant value you're trying to match.
And of course, Jon's initial warning still holds true: while doing floating-point logic, you could very easily end up with a value that should be -pi/2, but which isn't exactly -pi/2, in which case your check will fail. Here be dragons.
Perhaps try:
const var SomeVar = (-Math.PI / 2).ToString();
switch (Rotation.ToString())
{
case SomeVar:
// some code
break;
}

Categories