I'm trying to make a simple switch case console menu for a few different users: admin, moderator, and user. admin would have create, delete, modify, show functions, moderator - create, modify, show functions, and user - create, show functions to choose from.
Admin switch case:
if(userType == "admin")
{
string i = Console.ReadLine();
switch(i):
case "create": Console.WriteLine("Created");
break;
case "modify": Console.WriteLine("Modified");
break;
case "delete":Console.WriteLine("Deleted");
break;
case "show":Console.WriteLine("Showed");
break;
default: Console.WriteLine("Default");
break;
}
Moderator switch case:
if(userType == "moderator")
{
string i = Console.ReadLine();
switch(i):
case "create": Console.WriteLine("Created");
break;
case "modify": Console.WriteLine("Modified");
break;
case "show": Console.WriteLine("Showed");
break;
default: Console.WriteLine("Default");
break;
}
User switch case:
if(userType == "user")
{
string i = Console.ReadLine();
switch(i):
case "create": Console.WriteLine("Created");
break;
case "show": Console.WriteLine("Showed");
break;
default: Console.WriteLine("Default");
break;
}
Is there any way to mold these switch cases into one dynamic switch? If I'm thinking or explaining something wrong, please correct me.
The dynamic equivalent of a switch-case is a dictionary lookup. For example:
Dictionary<string, Action> userActions = {
{ "create", () => Console.WriteLine("created") },
{ "show", () => Console.WriteLine("showed") } };
Dictionary<string, Action> adminActions = {
{ "create", () => Console.WriteLine("created") },
{ "show", () => Console.WriteLine("showed") },
{ "delete", () => Console.WriteLine("deleted") } };
Dictionary<string, Dictionary<string, Action>> roleCapabilities = {
{ "user", userActions },
{ "administrator", adminActions } };
roleCapabilities[userType][action]();
At runtime, you can easily add and remove allowed actions to each role (group).
In order to implement "default" logic, you'd use something like:
Action actionCall;
if (roleCapabilities[userType].TryGetValue(action, out actionCall)) {
actionCall();
}
else {
// this is the "default" block, the specified action isn't valid for that role
}
This is a good candidate for the strategy pattern.
In the strategy pattern, functionality is represented by an object of an interface that can be passed around. Different implementations allow the behaviour to change dynamically.
For example:
interface ConsoleInteractor
{
void performAction(string action);
}
class UserConsoleInteractor : ConsoleInteractor
{
public void performAction(string action)
{
switch(i)
{
case "create":
Console.WriteLine("Created");
break;
case "show":
Console.WriteLine("Showed");
break;
default:
Console.WriteLine("Default");
break;
}
}
}
you are better off with a map of functions or Actions.
var actionsAdmin = new Dictionary<string, Action>{
{"create", ()=>Console.WriteLine("create")}
{"modify", ()=>Console.WriteLine("modify")}
}
var actionsUser = new Dictionary<string, Action>{
{"show", ()=>Console.WriteLine("show")}
{"foodle", ()=>Console.WriteLine("foodle")}
}
then choose the right map and execute the named function
var action = actionUser[verb];
action();
Switch (no pun intended) it around do check for role at each case. And then if it is not allowed to do it, skip it.
string i = Console.ReadLine();
if (allowed(userType, i)){
switch(i):
case "create": Console.WriteLine("Created");
handleCreate();
break;
case "show":Console.WriteLine("Showed");
handleShow();
break;
case "delete":Console.WriteLine("Deleted");
handleDelete();
break;
default: Console.WriteLine("Default");
handleDefault(userType);
break;
}
Related
I have a big switch statement that has a cyclomatic complexity of 31 and it must be refactorized to at least 25.
This is the error: Severity Code Description Project File Line Suppression State Suppression State
Error CA1502 'Worker.StartListening()' has a cyclomatic complexity of 31. Rewrite or refactor the method to reduce complexity to 25.
Thank you!
Here is the code:
public void StartListening()
{
var consumerSettingsSection= this.configurationManager.GetSection<ConsumerSettingsSection>("appZ/consumer");
foreach (var setting in consumerSettingsSection.QueueSettings)
{
var eventType = ConsumedEventType.NotSpecified;
switch (setting.Name)
{
case "A":
eventType = ConsumedEventType.A;
break;
case "B":
eventType = ConsumedEventType.B;
break;
case "C":
eventType = ConsumedEventType.C;
break;
case "D":
eventType = ConsumedEventType.D;
break;
case "E":
eventType = ConsumedEventType.E;
break;
case "F":
eventType = ConsumedEventType.F;
break;
case "G":
eventType = ConsumedEventType.G;
break;
case "H":
eventType = ConsumedEventType.H;
break;
case "I":
eventType = ConsumedEventType.I;
break;
case "J":
eventType = ConsumedEventType.J;
break;
case "K":
eventType = ConsumedEventType.K;
break;
case "L":
eventType = ConsumedEventType.L;
break;
default:
eventType = ConsumedEventType.NotSpecified;
break;
}
var consumer = new ChannelConsumer(setting, eventType);
consumer.MessageConsumed += this.Consumer_MessageConsumed;
consumer.StartConsuming();
}
}
You can try to simplify your code using Enum.TryParse method:
if (Enum.TryParse(setting.Name, true, out eventType))
return eventType;
else
return ConsumedEventType.NotSpecified;
You can parse the setting.Name string to ConsumedEventType, use the parsed value, otherwise return ConsumedEventType.NotSpecified value.
It's easier than maintaining a list of values. In terms of your code above you can write something like that
foreach (var setting in consumerSettingsSection.QueueSettings)
{
var eventType = ConsumedEventType.NotSpecified;
if (Enum.TryParse(setting.Name, true, out ConsumedEventType parsedEvent))
{
eventType = parsedEvent;
}
//rest of code
}
Or even easier
if (!Enum.TryParse(setting.Name, true, out ConsumedEventType eventType))
{
eventType = ConsumedEventType.NotSpecified;
}
Please, keep in mind that inline out variables are supported starting from C# 7
Use a Dictionary<string, ConsumedEventType>:
var d = new Dictionary<string, ConsumedEventType>()
{
{ "A", ConsumedEventType.A },
{ "B", ConsumedEventType.B },
{ "C", ConsumedEventType.C },
...
}
Now get the actual value that fits your settings.Name:
ConsumedEventType type;
var type = !d.ContainsKey(settings.Name)
ConsumedEventType.NotSpecified :
d[setting.sName];
Let's assume there are a lot of code blocks like this in my solution:
switch (Key)
{
case "A":
displayName = "Title1";
break;
case "B":
displayName = "Title2";
break;
case "C":
displayName = "Title3";
break;
default:
throw new NotSupportedException();
}
displayName = displayName.X();
Is there a possibility to get all strings in code on which method X can be executed?
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
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";
}
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.