I want something like the switch statement (but different of course) - c#

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;
}

Related

How to get the month name using Dictionary in C#?

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];

How to simplify a switch statement to reduce the cyclomatic complexity

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];

Finding all objects on which method X is executed

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?

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";
}

C# Parse SqlDbType Conversion

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.

Categories