is there any way to simplify this double conditional clauses structure? - c#

for example
if (x=="A)
switch (y)
{
case "1": Do1();break;
case "2": Do2();break;
case "3": Do3();break;
}
else if (x=="B")
switch (y)
{
case "1": Do4();break;
case "2": Do5();break;
case "3": Do6();break;
}
else
switch (y)
{
case "1": Do7();break;
case "2": Do8();break;
case "3": Do9();break;
}
I wish I could do the following, however it has many redundant checks.
if (x=="A" && y=="1")
Do1();
else if (x=="A" && y=="2")
Do2();
else if (x=="A" && y=="3")
Do3();
else if (x=="B" && y=="1")
Do4();
else if (x=="B" && y=="2")
Do5();
else if (x=="B" && y=="3")
Do6();
else if (x=="C" && y=="1")
Do7();
else if (x=="C" && y=="2")
Do8();
else if (x=="C" && y=="3")
Do9();

Suggestion to introduce OOPS is really great, please do not ignore that comment. For time being you can write your code like this.
var combinedText = x+y;
switch(combinedText)
{
case "A1": Do1(); break;
case "A2": Do2(); break;
case "A3": Do3(); break;
case "B1": Do4(); break;
case "B2": Do5(); break;
case "B3": Do6(); break;
case "C1": Do7(); break;
case "C2": Do8(); break;
case "C3": Do9(); break;
}

Your code currently has two responsibilities - deciding what set of methods to execute (varible x) and deciding which exact method to execute (varible y). Simplest option to make code much more clear - split this responsibilities and extract methods, that will decide which method from set of methods to call
switch (x)
{
case "A": DoA(y); break;
case "B": DoB(y); break;
default:
DoDefault(y); break;
}
Now your caller code is simple. And here is one of DoX methods:
private void DoA(string y)
{
switch (y)
{
case "1": Do1(); break;
case "2": Do2(); break;
case "3": Do3(); break;
}
}
Other option is to make .net to decide which set of methods to call, by using polymorphism. But in your simple case with only one switch(x) block, I will not recommend to do that. If your real code is more complex, then consider to extract classes which will hold set of functionality (Do1, Do2, Do3) and will decide upon that functionality execution. E.g. calling code:
IDo ido = CreateIDo(x);
ido.Do(y);
Yes, that's all. Extremely clean. Here is IDo interface creation code:
public static IDo CreateIDo(string x)
{
switch (x)
{
case "A": return new A();
case "B": return new B();
default:
return new C();
}
}
And here is class A, that encapsulates first set of methods and decisions upon executing them:
public interface IDo
{
void Do(string y);
}
public class A : IDo
{
public void Do(string y)
{
switch (y)
{
case "1": Do1(); break;
case "2": Do2(); break;
case "3": Do3(); break;
}
}
private void Do1() { }
private void Do2() { }
private void Do3() { }
}
Again, use this in case your real code is more complex.

I would use an IEnumerable collection of Tuples and an Action delegate to define your list of methods to be called, create the list as a private field or in the class initialiser, or to be flexible you can add Tuples to a public property as needed. If you need to pass in parameters use one of the overloaded versions of the Action delegate ie: Action(t1, t2) etc.
If you need a return value use the Func delegate as per the other answer.
IEnumerable<Tuple<string, string, Action>> actions = new List<Tuple<string, string, Action>>() {
Tuple.Create<string, string, Action>("A", "1", SomeMethod1),
Tuple.Create<string, string, Action>("A", "2", SomeMethod2)
};
string x = "A";
string y = "2";
var action = actions.FirstOrDefault(t => ((t.Item1 == x) && (t.Item2 == y)));
if (action != null)
action.Item3();
else
DoSomeDefaultMethod();
public void SomeMethod1() { // Whatever you want to do }
public void SomeMethod2() { // Whatever you want to do }
public void DoSomeDefaultMethod() { // Default Method }

void Main()
{
Dictionary<string, Action> d = new Dictionary<string, Action>()
{
{"A1", Do1},
{"A2", Do2},
{"A3", Do3},
{"B1", Do4},
{"B2", Do5},
{"B3", Do6},
{"1", Do7},
{"2", Do8},
{"3", Do9}
};
var x = "A";
var y = "1";
var action = x == "A" || x == "B" ? x + y : y;
if (d.ContainsKey(action))
d[action]();
}
public void Do1() {}
public void Do2() {}
public void Do3() {}
public void Do4() {}
public void Do5() {}
public void Do6() {}
public void Do7() {}
public void Do8() {}
public void Do9() {}
EDIT
I remembered about this fluent functional switch:
var sw = new Switch<string>(action)
.Case("A1", s => Do1())
.Case("A2", s => Do2());

Consider this if you don't want to change much of your current structure,(and don't want to create new types etc.)
Add them to tuples like below
var tuples = new List<Tuple<string,string,Func<>>()>(); // Func should be of your Do() type
Add your conditional data with the related funcs to the list
tuples.Add(new Tuple<string,string,Func<>>("A","1", Do1()));
...
Just call it when required using your conditionals directly
var function = tuples.Where(x => x.item1 == "A" && x.item2 == "1").Select(x => x.item3);
function.Invoke(); // to call it.
Now if you got more conditionals in future, you can just add them to the list without changing any code.

Use some thing like this . only three if would do.
if (x == "A")
{
int a = (y == "1") ? do1() : ((y == "2") ? do2() : do3());
}
}
int do1() { return 10; }
int do2() { return 10; }
int do3() { return 10; }

I guess the same kind of switch on X is performed in more than one place in your code, if so kindly refactor it and use polymorphism instead
If X is string first replace the typecode with class and use polymorphism.

Related

Faster way to compare enums?

I'm looking for a better way to compare enums. Currently, I have an enum with 3 different possible values:
public enum Elements { fire, water, earth };
However, an example of a function where something happens when two Elements collide:
Public Void ElementCollisionExample(Elements element1, Elements element2){
if (element1 == Elements.fire){
if (element2 == Elements.fire){
//Do stuff
} else if (element2 == Elements.water){
// Do stuff
} else {
// Do stuff
}
} else if (element2 == Elements.water){...etc...}
}
And that is only for the Fire Element!
I've searched a while, and looked on similar SO questions, but I'm not sure how to formulate the problem. All I've found are questions such as "Is '==' or '.Equals()' faster to compare Enums???", which is entirely different.
Is there an easy way to do this? I already have these conditions being handled in a separate Manager, but it still irritates me.
EDIT:
A combination of elements always has the same outcome. So Fire + Water = X, and Water + Fire = X as well.
It will be cleaner code with C# switch conditions introduced in C# 7.0.
public void ElementCollisionExample(Elements element1, Elements element2)
{
// Do nothing on equal elements
if (element1 == element2) return;
switch (element1)
{
case Elements.fire when element2 == Elements.water:
case Elements.water when element2 == Elements.fire:
// Do stuff
break;
case Elements.fire when element2 == Elements.earth:
case Elements.earth when element2 == Elements.fire:
// Do stuff
break;
case Elements.water when element2 == Elements.earth:
case Elements.earth when element2 == Elements.water:
// Do stuff
break;
}
}
Updated: Order of element1 and element2 does not matter. Also ignoring equal elements.
One option is to have a dictionary of actions you can invoke. For example:
public class ElementActionFactory
{
// Somewhere to keep our actions, using tuple to pair up elements
private Dictionary<(Elements, Elements), Action> _elementActions;
public ElementActionFactory()
{
// Initialise the action dictionary
_elementActions = new Dictionary<(Elements, Elements), Action>
{
{(Elements.Fire, Elements.Fire), FireAndFire},
{(Elements.Fire, Elements.Water), FireAndWater},
{(Elements.Fire, Elements.Earth), FireAndEarth},
// etc.
};
}
public void Invoke(Elements element1, Elements element2)
{
// Try to get the action, and if we don't find it...
if (!_elementActions.TryGetValue((element1, element2), out var action))
{
// reverse the arguments and try again - this assumes the order is not important
if (!_elementActions.TryGetValue((element2, element1), out action))
{
return; //No action was found
}
}
// Actually run the method now
action.Invoke();
}
public void FireAndFire()
{
Console.WriteLine("Fire And Fire");
}
public void FireAndWater()
{
Console.WriteLine("Fire And Water");
}
public void FireAndEarth()
{
Console.WriteLine("Fire And Earth");
}
}
And to use it, it's simply:
var elementActionFactory = new ElementActionFactory();
var element1 = Elements.Fire;
var element2 = Elements.Water;
elementActionFactory.Invoke(element1, element2);
Assuming that the order in which the elements are combined does not matter, you could treat the enumeration as a bit field, that is, a set of flags - so you can combine them allowing you to have a simple switch. For example:
[Flags]
public enum Elements
{
none = 0b0000_0000_0000,
fire = 0b0000_0000_0001,
water = 0b0000_0000_0010,
earth = 0b0000_0000_0100
};
public void ElementCollisionExample(Elements element1, Elements element2)
{
switch (element1 | element2)
{
case Elements.fire | Elements.water:
Console.WriteLine("The fire is extinguished");
break;
case Elements.earth | Elements.fire:
Console.WriteLine("The earth goes black");
break;
}
}
For Cleaner Code i suggest using complex switch ...
Elements x, y;
switch (x)
{
case Elements.fire:
switch (y)
{
case Elements.fire:
break;
case Elements.water:
break;
case Elements.earth:
break;
}
break;
case Elements.water:
switch (y)
{
case Elements.fire:
break;
case Elements.water:
break;
case Elements.earth:
break;
}
break;
case Elements.earth:
switch (y)
{
case Elements.fire:
break;
case Elements.water:
break;
case Elements.earth:
break;
}
break;
}
With tuples, you can avoid the nested ifs:
public void ElementCollisionExample(Elements element1, Elements element2)
{
Tuple<Elements,Elements> elements = Tuple.Create(element1,element2);
if(elements.Equals(Tuple.Create(Elements.fire, Elements.earth))
{
//do something
}
else if(elements.Equals(Tuple.Create(Elements.fire, Elements.water))
{
// do something
}
// and so on
}
You can simplify it more if you create a separate function:
public void ElementCollisionExample(Elements element1, Elements element2)
{
Tuple<Elements,Elements> elements = Tuple.Create(element1,element2);
if(CompareElements(elements, Elements.fire, Elements.earth))
{
//do something
}
else if(CompareElements(elements, Elements.fire, Elements.water))
{
// do something
}
// and so on
}
private bool CompareElements(Tuple<Elements,Elements> actual, Elements expected1, Elements expected2)
{
return actual.Equals(Tuple.Create(expected1, expected2));
}

How to store outcome of switch statement into an object in c#

Is it possible to create an object that stores the outcome of the switch statement in c#? Because my end goal is to compare the object in an if statement, and if that's true then it will print a writeline.
switch (results)
{
case 1:
checkingWriter.WriteLine("text");
break;
case 0:
checkingWriter.WriteLine("text");
error_Found = true;
break;
case -1:
checkingWriter.WriteLine("text");
error_Found = true;
break;
case -2:
checkingWriter.WriteLine("text");
error_Found = true;
break;
case -3:
checkingWriter.WriteLine("text");
error_Found = true;
break;
}
You are mixing both side effects and the computation of a value; this is a bad code smell and you might consider separating that logic.
To address your specific question: at this time there is no easy way to get a value computed by a particular switch case section out of the switch. However, this feature has been proposed for C# 8.0, so it seems likely that you'll get some version of this. See the link below for the proposal:
https://neelbhatt.com/2018/05/19/c-8-0-expected-features-part-iii-switch-statments/
Yes, something like (but very basic since we do not have any details):
var objectToCheck = ...; // Some initialized value or null
switch(...)
{
case ...:
objectToCheck = ...
break;
case ...:
objectToCheck = ...
break;
...
default:
Error handling
}
if (objectToCheck ==/.Equals(...) ) // Check object
create variable before switch statement begins, store the switch case result in variable. After switch ends, use the variable in the if condition.
var result = null;
switch (caseSwitch)
{
case 1:
result = fn1();
break;
case 2:
result = fn2();
break;
default:
Console.WriteLine("Default case");
break;
}
if(result == 'your condition')
do something
There are not enough details but may this works, or give you a new idea:
public class Foo
{
public static bool operator !=(Foo foo1, int results){
return results <= 0;
}
public static bool operator ==(Foo foo1, int results){
switch(results)
{
case 1:
Console.WriteLine("All gones good");
return false;
case 0:
Console.WriteLine("Nothing happend");
break;
case -1:
Console.WriteLine("Error 183");
break;
case -2:
Console.WriteLine("Fatal Error");
break;
case -3:
Console.WriteLine("The user doesn't exists");
break;
default:
return false;
}
return true;
}
}
And when you use it:
public static void Main()
{
Foo foo = new Foo();
int results = 0;
// makes some logic that fills results
if(foo == results){
Console.WriteLine("Do Something Custom Here");
}
results = -1;
if(foo == results){
Console.WriteLine("Do Another Something Custom Here");
}
}
It will give you in console something like this:
//Nothing happend
//Do Something Custom Here
//Error 183
//Do Another Something Custom Here

Get column index as constant value

Currently i am having code like this inside dataGridView1_CellValidating event:
if(e.ColumnIndex == dataGridView1.Columns["FIRST"].Index)
{
// Some code
}
else if(e.ColumnIndex == dataGridView1.Columns["Second"].Index)
{
// Some code
}
else if(e.ColumnIndex == dataGridView1.Columns["Third"].Index)
{
// Some code
}
And it is like this because i cannot use it in switch statement like:
switch(e.ColumnIndex)
{
case dataGridView.Columns["First"].Index:
break;
case dataGridView.Columns["Second"].Index:
break;
case dataGridView.Columns["Third"].Index:
break;
}
returns me error on case line Expecting constant value.
So how can i make this work?
The switch statement is complaining because the “case” portion of the statement “requires” a “CONSTANT” value. The statement dataGridView.Columns["First"].Index will always return the same value… unless you move the column… which you can do. This is why the compiler is going to look at the retuned value from dataGridView.Columns["First"].Index as NOT a “constant”.
This makes sense in the fact that the “column index” for the column named “First” could be at ANY column index in the grid… Hence the error.
A possible solution is to grab the current columns “Name” string value then switch off the column “Name” like below.
string columnName = dataGridView.Columns[e.ColumnIndex].Name;
switch (columnName) {
case "First":
MessageBox.Show("Cell Validated is in 'FIRST' column");
break;
case "Second":
MessageBox.Show("Cell Validated is in 'Second' column");
break;
case "Third":
MessageBox.Show("Cell Validated is in 'Third' column");
break;
}
If you really want to use switch you can make use of pattern matching in switch case
PS: For C# 7.0 or above
switch(e.ColumnIndex)
{
case var _ when (dataGridView.Columns["First"].Index == e.ColumnIndex):
break;
case var _ when (dataGridView.Columns["Second"].Index == e.ColumnIndex):
break;
case var _ when (dataGridView.Columns["Third"].Index == e.ColumnIndex):
break;
}
Maybe, you first make constant values and assign dataGridView.Columns["First"].Index to it.
For example:
int a = {given index}
const int IndexOfFirstCol = dataGridView.Columns["First"].Index;
const int IndexOfSecCol = dataGridView.Columns["Second"].Index;
then,
switch(a)
{
case IndexOfFirstCol:
//do smth
break;
case IndexOfSecCol:
//do smth
break;
}
If you cannot use pattern matching from C# 7.0, there is also another way by using dictonaries where your keys are functions checking the conditions (cases) and the values are the actions you want to perform. For your code it would look like:
private void dataGridView1_CellValidating(object sender, DataGridViewCellValidatingEventArgs e)
{
var caseDictionary = new Dictionary<Func<bool>, Action>()
{
{ () => (e.ColumnIndex == dataGridView1.Columns["First"].Index), () => { MessageBox.Show("First");}},
{ () => (e.ColumnIndex == dataGridView1.Columns["Second"].Index), () => { MessageBox.Show("Second");}},
{ () => (e.ColumnIndex == dataGridView1.Columns["Third"].Index), () => { MessageBox.Show("Third");}}
};
caseDictionary.Where(caseRecord => caseRecord.Key()).Select(action => action.Value).FirstOrDefault()?.Invoke();
}
You could of course declare the Dictionary in your constructor and just call it in the CellValidating event.
I would have another approach, using a Dictionnary (from the namespace System.Collections.Generic) of methods built in such way
The key is the index of the column in the datagridview ("First", "Second" ...)
The value is a Delegate to the method to do (what replaces your // some code in each if/else if
In example :
/*
* This example is written for console application, that can be tested easily.
* The logic can be rewritten for WinForm
*/
static void TheFirstCase()
{
//This should be replaced by the differents actions you want to do
Console.WriteLine("first case");
}
static void TheSecondtCase()
{
Console.WriteLine("second case");
}
static void TheThirdCase()
{
Console.WriteLine("third case");
}
static void Main(string[] args)
{
Dictionary<string, Delegate> MyDic = new Dictionary<string, Delegate>
{
//If you need parameters in the TheFirstCase(), use new Action<TypeOfTheFirstParam, TypeOfTheSecondParam, ...>(TheFirstCase)
//If your Method needs to return something, use Func instead of Action
{ "First", new Action(TheFirstCase) },
{ "Second", new Action(TheSecondtCase) },
{ "Third", new Action(TheThirdCase) }
};
// in your question, this is e.ColumnIndex
var ValueInColIndex = 42;
// in your question, this is dataGridView.Columns
var DataGridViewDatas = new Dictionary<string, int>
{
{ "First", 0 },
{ "Second", 42 },
{ "Third", 69 }
};
foreach (var MyAction in MyDic)
{
if (DataGridViewDatas[MyAction.Key] == ValueInColIndex)
{
MyAction.Value.DynamicInvoke();
}
}
}
Outputs :
second case

C# Switch-case string end with

Is there any way to make a case condition in a switch statement where you say if a string end with something?
switch (Pac.Sku)
{
case "A":
pacVM.Sucursal = "Managua";
break;
case "B":
pacVM.Sucursal = "Masaya";
break;
case "C":
pacVM.Sucursal = "Leon";
break;
default:
pacVM.Sucursal = "N/A";
break;
}
Get the last character of the string, and switch over the result:
switch (Pac.Sku.Last())
{
case 'A':
pacVM.Sucursal = "Managua";
break;
case 'B':
pacVM.Sucursal = "Masaya";
break;
case 'C':
pacVM.Sucursal = "Leon";
break;
default:
pacVM.Sucursal = "N/A";
break;
}
If the string could be null or empty use something like this function instead of Last(). This function returns null if the string is null, null if the string is empty, and the last character of the string if it is not null or empty:
char? GetLast(string s)
{
return s?.Length > 0 ? s.Last() : (char?)null;
}
Switch:
switch(GetLast(Pac.Sku))
You can
use pattern matching feature of C# 7.0 to achieve this. Here is a very basic example:
var t = "blah";
switch (t)
{
case var a when t.EndsWith("bl"):
Console.WriteLine("I'm not here");
break;
case var b when t.EndsWith("ah"):
Console.WriteLine("I'm here");
break;
}
You can get creative with a Func<string, string>[] like this:
Func<string, string>[] cases = new Func<string, string>[]
{
x => x.EndsWith("A") ? "Managua" : null,
x => x.EndsWith("B") ? "Masaya" : null,
x => x.EndsWith("C") ? "Leon" : null,
x => "N/A",
};
Func<string, string> #switch = cases.Aggregate((x, y) => z => x(z) ?? y(z));
string result = #switch(Pac.Sku);
I have tested this with sample input that matches each of the cases and it works just fine.
One significant advantage with this approach is that you can build the Func<string, string>[] at run-time. Nice for creating configurable solutions.
You're also not limited to just using EndsWith - any condition can be used that suits the purpose.
I think it's not a way!
You can only use the if-else
if (Pac.Sku.EndsWith("A") )
{
pacVM.Sucursal= "Managua";
}
else if (Pac.Sku.EndsWith("B"))
{
pacVM.Sucursal= "Masaya";
}
else if (Pac.Sku.EndsWith("C"))
{
pacVM.Sucursal= "Leon";
}
else
{
pacVM.Sucursal= "N/A";
}

I need to replace a C# switch with something more compact

I have the following code:
switch (pk.Substring(2, 2))
{
case "00":
ViewBag.Type = _reference.Get("14", model.Type).Value;
break;
case "01":
ViewBag.Type = _reference.Get("18", model.Type).Value;
break;
}
It does the job but does not look very clean to me. Is there some way I could make this code a bit smaller. I was thinking to just have the number 14 or 18 as a variable but I am not sure the best way to code if I should use if-else or some other way.
You could use a static dictionary as a map instead of a switch-statement.
static readonly Dictionary<string, string> map = new Dictionary<string, string> {
{ "00", "14" },
{ "01", "18" },
// ... more ...
};
// ... in your method ...
string str = pk.Substring(2, 2);
string val;
if (!map.TryGetValue(str, out val))
{
// Handle error, like in the "default:" case of the switch statement
}
else
{
ViewBag.Type = _reference.Get(val, model.Type).Value;
}
However, I would only do this, if there are really a lot of mappings that maybe can even be "read" from an external source like a configuration file.
Also note, that if the "key" is really a consecutive sequence of integers starting at 0, you might be able to use an array, where the "key" is simply the index into it.
static readonly string[] map = new string[] {
"14", "18", ...
};
int index = Int32.Parse(pk.Substring(2, 2)); // Error handling elided.
if (index < 0 || index > map.Length)
{
// Handle error, like in the "default:" case of the switch statement
}
else
{
ViewBag.Type = _reference.Get(map[index], model.Type).Value;
}
Otherwise rather stay with an explicit switch statement (possibly factoring out the assignment for more terse code):
string val;
switch (pk.Substring(2, 2))
{
case "00":
val = "14";
break;
case "01":
val = "18";
break;
// ... more ...
default:
// Error handling for unknown switch-value.
break;
}
ViewBag.Type = _reference.Get(val, model.Type).Value;
It seems that there is some relationship between "00"->"14" and "01"->"18". I believe this relationship results from the business logic. You should wrap the logic and make the code in your controller clear. Finally the code in the controller should look like:
public ActionResult MyAction()
{
//some code
ViewBag.Type = TypeProvider.GetType(pk, model.Type);
//return something
}
class TypeProvider
{
Dictionary<string, string> relations = ...
//a dictionary stores "00"->"14" logics
public static SomeType GetType(string pk, Type modelType)
{
return _reference.Get(relations[pk.SubString(2,2)], modelType).Value;
}
}
var data = pk.Substring(2, 2);
var choice = data == "00" ? "14" : (data=="01"?"18":"");
if (choice != string.Empty) ViewBag.Type = _reference.Get(choice, model.Type).Value;
I use mapping extensions fot that kind of code:
ViewBag.Type = pk.Substring(2, 2)
.Map("00", x => GetViewBagValue("14"))
.Map("01", x => GetViewBagValue("18"))
and in your case this method:
private ViewBagValue GetViewBagValue(string value)
{
return _reference.Get(value, model.Type).Value;
}
I use this. You could easily change it to generic or use e.g. object[] instead. Not super efficient, but very compact:
public static class Util {
public static string Switch(string value, params string[] nameValues) {
for (int x = 0; x < nameValues.Length; x += 2) {
if (nameValues[x] == value) {
return nameValues[x + 1];
}
}
return string.Empty;
}
}
Then just call that like this:
var res = Util.Switch("test2", "test1", "res1", "test2", "res2");
Best of luck!

Categories