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];
Related
I have implemented the first three letters of the month to full name of the month in get Full Month function it is returned based on three letters .
But how to implemented in Dictionary concept Any one simplify modify this code given below code:
**public static string getFullMonth(string mthname)
{
string Mthname = "";
switch (mthname.ToUpper())
{
case "JAN":
Mthname ="January";
break;
case "FEB":
Mthname = "February";
break;
case "MAR":
Mthname = "March";
break;
case "APR:":
Mthname = "April";
break;
case "MAY":
Mthname = "May";
break;
case "JUN":
Mthname = "June";
break;
case "JUL":
Mthname = "July";
break;
case "AUG":
Mthname = "August";
break;
case "SEP":
Mthname = "September";
break;
case "OCT":
Mthname = "October";
break;
case "NOV":
Mthname = "November";
break;
case "DEC":
Mthname = "December";
break;
default:
Console.WriteLine("Invalid grade");
break;
}
return Mthname;
}**
simplify this code given below code
Yes, don't use a dictionary at all:
public static string GetFullMonth(string englishShortMonthName)
{
CultureInfo englishCulture = CultureInfo.InvariantCulture;
if (DateTime.TryParseExact(englishShortMonthName, "MMM", englishCulture, DateTimeStyles.None, out DateTime dt))
return dt.ToString("MMMM", englishCulture);
return englishShortMonthName;
}
Read about the month ("M", "m") format specifier
Look up Dictionary syntax. Ultimately you're looking for something like this:
var monthNames = new Dictionary<string, string>
{
{ "JAN", "January" },
{ "FEB", "February" },
...
}
Please find complete solution
public static string getFullMonth(string mthname)
{
var monthNames = new Dictionary<string, string>
{
{ "JAN", "January" },
{ "FEB", "February" },
...
}
return monthNames[mthname];
}
But above code looks weird So You should create dictionary globally and initialize in constructor.
Add only below line in getFullMonth function.
return monthNames[mthname];
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?
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;
}
Is there any way to do something like this:
(SqlDbType.Int).Parse(dtbDataTable.Rows[0]["Id"])
Posting back my workaround:
public static string ParseValue(SqlDbType psdtParameter, string pstrValue, string pstrDateFormat = null)
{
object objReturn = new object();
if (pstrValue != "")
{
switch (psdtParameter.ToString())
{
case "BigInt":
objReturn = TypeDescriptor.GetConverter(typeof(Int64)).ConvertFromString(pstrValue);
break;
case "Bit":
objReturn = TypeDescriptor.GetConverter(typeof(Boolean)).ConvertFromString(pstrValue);
break;
case "NText":
case "NVarChar":
case "VarChar":
case "NChar":
case "Text":
case "Char":
objReturn = TypeDescriptor.GetConverter(typeof(String)).ConvertFromString(pstrValue);
break;
case "SmallDateTime":
case "DateTime":
objReturn = DateTime.ParseExact(pstrValue, pstrDateFormat, CultureInfo.InvariantCulture);
//TypeDescriptor.GetConverter(typeof(DateTime)).ConvertFromString(pstrValue);
break;
case "Money":
case "SmallMoney":
case "Decimal":
objReturn = TypeDescriptor.GetConverter(typeof(Decimal)).ConvertFromString(null, CultureInfo.InvariantCulture, pstrValue);
break;
case "Float":
objReturn = TypeDescriptor.GetConverter(typeof(Double)).ConvertFromString(pstrValue);
break;
case "Binary":
case "VarBinary":
case "Timestamp":
case "Image":
objReturn = TypeDescriptor.GetConverter(typeof(Byte[])).ConvertFromString(pstrValue);
break;
case "Int":
objReturn = TypeDescriptor.GetConverter(typeof(Int32)).ConvertFromString(pstrValue);
break;
case "Real":
objReturn = TypeDescriptor.GetConverter(typeof(Single)).ConvertFromString(pstrValue);
break;
case "SmallInt":
objReturn = TypeDescriptor.GetConverter(typeof(Int16)).ConvertFromString(pstrValue);
break;
case "TinyInt":
objReturn = TypeDescriptor.GetConverter(typeof(Byte)).ConvertFromString(pstrValue);
break;
}
return objReturn.ToString();
}
else
{
return null;
}
}
Tks!
Unfortunately no. SqlDbType is an enum, so (SqlDbType.Int) actually boils down to an integer value, not a type. The only way I can think of to do this is some sort of switch statement:
switch (SqlDbType dbType)
{
case SqlDbType.Int:
int value = Int32.Parse(dtbDataTable.Rows[0]["Id"]);
//Do stuff with this value
//repeat for other types
}
I think that would be tough to do, and it's not the most readable way. I handle this via extension methods to help with TinyInt, SmallInt, and nullable values across the board. E.g.:
using (var dr = new SafeDataReader(cmd.ExecuteReader()) {
while (dr.Read()) {
int? id = dr.GetNullableIntFromSqlTinyInt(0);
// Other stuff like that to handle type conversions
}
}
SafeDataReader is part of the CSLA business object framework, but you could implement your own DataReader if you would like. It's a lot more legible and encapsulates all the parsing logic behind the scenes to the extension method.
Is there a C# construct like the switch statement that allows control to fall through the next level? I have something like this:
public static IEnumerable<string> SeverityOrHigher(string severity)
{
var result = new List<string>();
switch (severity.ToUpper())
{
case "ALL":
result.Add("ALL");
case "DEBUG":
result.Add("DEBUG");
case "INFO":
result.Add("INFO");
case "WARN":
result.Add("WARN");
case "ERROR":
result.Add("ERROR");
case "FATAL":
result.Add("FATAL");
case "OFF":
result.Add("OFF");
default:
break;
}
return result;
}
...which clearly does not work in C#, (Control cannot fall through from one case label...) yet it seems to me like it should. I know it expects breaks in there, but that would not give me the data flow I'm looking for. What can be done to make this happen the way I'd like?
In your case you can emulate "falling case" with a little bit of LINQ:
public static IEnumerable<string> SeverityOrHigher(string severity)
{
var result = new List<string>()
{ "ALL", "DEBUG", "INFO", "WARN", "ERROR", "FATAL", "OFF" };
return result.SkipWhile(l => l != severity.ToUpper()).ToArray();
}
Along with gotos, etc, you could do with this an enum and a bit of linq:
public static IEnumerable<Severity> SeverityOrHigher(Severity severity)
{
var value = (int) severity;
return Enum.GetValues(typeof (Severity))
.Cast<int>()
.Where(i => i >= value)
.Select(i => (Severity) i);
}
public enum Severity
{
All = 0,
Trace = 1,
Debug = 2,
Information = 3,
Warning = 4,
Error = 5,
Fatal = 6
}
It is not the optimal solution but you could use the goto statement like this:
switch (severity.ToUpper())
{
case "ALL":
result.Add("ALL");
goto case "DEBUG";
case "DEBUG":
result.Add("DEBUG");
goto case "INFO";
case "INFO":
result.Add("INFO");
goto case "WARN";
case "WARN":
result.Add("WARN");
goto case "ERROR";
case "ERROR":
result.Add("ERROR");
goto case "FATAL";
case "FATAL":
result.Add("FATAL");
goto case "OFF";
case "OFF":
result.Add("OFF");
break;
default:
break;
}
Use goto:
switch (severity.ToUpper())
{
case "ALL":
result.Add("ALL");
goto case "DEBUG";
case "DEBUG":
result.Add("DEBUG");
goto case "INFO";
case "INFO":
result.Add("INFO");
goto case "WARN";
case "WARN":
result.Add("WARN");
goto case "ERROR";
case "ERROR":
result.Add("ERROR");
goto case "FATAL";
case "FATAL":
result.Add("FATAL");
goto case "OFF";
case "OFF":
result.Add("OFF");
break;
default:
break;
}
Microsoft (implicitly) recommends this use: http://msdn.microsoft.com/en-us/library/06tc147t(v=vs.71).aspx
#nemesv's Linq answer is way better solution but if you want to do it with switch you could do like this and will get same result.
public static IEnumerable<string> SeverityOrHigher(string severity)
{
var lastFound = -1;
var severityList = new List<string>() { "ALL", "DEBUG", "INFO", "WARN", "ERROR", "FATAL", "OFF" };
var results = new List<string>();
foreach (var t in severityList)
{
if (lastFound > -1)
{
for (var index = lastFound + 1; index < severityList.Count; index++)
{
results.Add(severityList[index]);
}
return results;
}
switch (severity.ToUpper())
{
case "ALL":
results.Add(severity);
lastFound = 0;
break;
case "DEBUG":
lastFound = 1;
results.Add(severity);
break;
case "INFO":
lastFound = 2;
results.Add(severity);
break;
case "WARN":
lastFound = 3;
results.Add(severity);
break;
case "ERROR":
lastFound = 4;
results.Add(severity);
break;
case "FATAL":
lastFound = 5;
results.Add(severity);
break;
case "OFF":
lastFound = 6;
results.Add(severity);
break;
}
}
return results;
}
Test:
var list = SeverityOrHigher("ALL");
foreach (var severity in list)
{
Console.WriteLine(severity);
}
Console.ReadKey();
Does not look very nice, but could do the job for you:
string s = severity.ToUpper();
result.add("OFF");
if (s == "OFF")
return result;
result.add("FATAL");
if (s == "FATAL")
return result;
result.add("ERROR");
if (s == "ERROR")
return result;
// ...
result.add("ALL");
return result;
I'd go with somehting like creating another list which represents all valid severities and checking if the input severity is one of them:
public static IEnumerable<string> SeverityOrHigher(string severity)
{
var result = new List<string>();
var severities = new List<string> { "ALL", "DEBUG", "INFO", "WARN", "ERROR", "FATAL", "OFF" };
severity = severity.ToUpper();
if (severities.Contain(severity))
result.Add(severity);
return result;
}