Convert If Statement into Switch - c#

I have this If statement and I would like to move them into Case-Switch
Here is my if Stataments:
if (rResponse.ErrorCode[0] == 0x20 && rResponse.ErrorCode[1] == 0x03)
ErrorMsg = "COMM_FRAME_ERROR";
if (rResponse.ErrorCode[0] == 0x20 && rResponse.ErrorCode[1] == 0x04)
ErrorMsg = "JAM";
if (rResponse.ErrorCode[0] == 0x20 && rResponse.ErrorCode[1] == 0x05)
ErrorMsg = "NO_CARD";
How can I do that?

if (rResponse.ErrorCode[0] == 0x20) {
switch(rResponse.ErrorCode[1]) {
case 0x03:
ErrorMsg = "COMM_FRAME_ERROR";
break;
case 0x04:
ErrorMsg = "JAM";
break;
case 0x05:
ErrorMsg = "NO_CARD";
break;
}
}

If u want both in switch case:
switch(rResponse.Errorcode[0])
case 0x20:
switch(rResponse.ErrorCode[1]) {
case 0x03:
ErrorMsg = "COMM_FRAME_ERROR";
break;
case 0x04:
ErrorMsg = "JAM";
break;
case 0x05:
ErrorMsg = "NO_CARD";
break;
}
break;

Can omit or change the exception,
if (rResponse.ErrorCode[0] == 0x20)
{
switch (rResponse.ErrorCode[1])
{
case 0x03:
ErrorMsg = "COMM_FRAME_ERROR";
break;
case 0x04:
ErrorMsg = "JAM";
break;
case 0x05:
ErrorMsg = "NO_CARD";
break;
default:
throw new InvalidOperationException();
break;
}
}

switch(rResponse.Errorcode[0])
{
case 0x20:
switch(rResponse.ErrorCode[1])
{
case 0x03:
ErrorMsg = "COMM_FRAME_ERROR";
break;
case 0x04:
ErrorMsg = "JAM";
break;
case 0x05:
ErrorMsg = "NO_CARD";
break;
}
break;
}

You can try something like this..
switch (rResponse.ErrorCode[0] + rResponse.ErrorCode[1])
{
case (0x20 + 0x03):
ErrorMsg = "COMM_FRAME_ERROR";
break;
case (0x20 + 0x04):
....
}
though this may not suite all the situations,

Although with the information provided Itay's response might be best. But if this error portion is on a larger scale then maybe something as follows might be worth a go. (Similar approach, just makes it easy to add on.
private string GetError(byte response1, byte response2)
{
var ErrorMessage = "";
switch (response1)
{
case 0x20:
ErrorMessage = ParseCardErrors(response2);
break;
case 0x21:
ErrorMessage = ParseDeviceErrors(response2);
break;
default:
ErrorMessage = "Unknown Error";
}
return ErrorMessage;
}
private string ParseCardErrors(byte response)
{
switch(response)
{
case 0x03:
return "COMM_FRAME_ERROR";
case 0x04:
return "JAM";
case 0x05:
return "NO_CARD";
default:
return "Unknown card Error";
}
}
private string ParseDeviceErrors(byte response)
{
switch(response)
{
case 0x03:
return "COMM_FRAME_ERROR";
case 0x04:
return "Unplugged";
case 0x05:
return "No device";
default:
return "Unknown device Error";
}
}

I might be posting a very diffrent solution this question but it can answer #Robert question:
class Program
{
//This can be included in Seprate class also
public enum ErrorMessages
{
//Store any Values as Key and Pair
// Provide and easy way to update answers
Error1 = 1,
Error2 = 2,
Error3 = 3,
Error4 = 4
}
public static void Main()
{
ICollection<EnumValueDto> list = EnumValueDto.ConvertEnumToList<ErrorMessages>();
foreach (var element in list)
{
Console.WriteLine(string.Format("Key: {0}; Value: {1}", element.Key, element.Value));
}
Console.Read();
/* OUTPUT:
Key: 1; Value: Error1
Key: 2; Value: Error2
Key: 3; Value: Error3
Key: 4; Value: Error4
*/
}
public class EnumValueDto
{
public int Key { get; set; }
public string Value { get; set; }
public static ICollection<EnumValueDto> ConvertEnumToList<T>() where T : struct, IConvertible
{
if (!typeof(T).IsEnum)
{
throw new Exception("Type given T must be an Enum");
}
var result = Enum.GetValues(typeof(T))
.Cast<T>()
.Select(x => new EnumValueDto
{
Key = Convert.ToInt32(x),//values are arbitary here any datatype will work
Value = x.ToString(new CultureInfo("en"))
})
.Where(err => err.Key==3) //Instead of 3 as key here use Response variable instead
.ToList()
.AsReadOnly();
return result;
}
}
}

Related

Creating a lexer and basic parser to extract class names, methods names, method parameters, etc

General task/idea
I'm currently trying to create a couple of lexers to extract functions/method names as well as class names and namespaces from different languages.
The goal is to be able to extract all defined classes, functions/methods, and namespaces to easily generate a overview for documentation and statistics.
As a starting point i chose PowerShell.
I created a basic lexer to tokenize my input.
I'm unsure where to go from here and if i'm doing it correctly.
Since I don't want to actually parse the language and generate code / interpret it, I won't really need to implement a full syntax analyzer and AST in my understanding.
My idea is to only check for certain pre-defined keywords like function, class, namespace, etc...
Question
Please help me stay in the correct direction as this is the first time I'm doing something like that and I'm really unsure how to proceed from now on.
Is my tokenizer correct, or did I mess up something?
Code
internal class TestLexer
{
private int _pos;
private string _input;
public class Token
{
public TokenType TokenType { get; }
public string Value { get; }
public Token(TokenType tokenType, string value)
{
TokenType = tokenType;
Value = value;
}
}
public enum TokenType
{
Variable,
OpenBrace,
CloseBrace,
Assignment,
Identifier,
Comment,
Equals,
NotEquals,
MultiLineCommentStart,
MultiLineCommentEnd,
Type,
Number
}
public IEnumerable<Token> Tokenize()
{
while (_pos < _input.Length)
{
var currentChar = _input[_pos];
if (char.IsWhiteSpace(currentChar)) {
_pos++;
continue;
}
switch (currentChar)
{
case '$':
{
_pos++;
yield return new Token(TokenType.Variable, "$");
break;
}
case '=':
{
_pos++;
yield return new Token(TokenType.Assignment, "=");
break;
}
case '#':
{
if (currentChar + 1 < _input.Length) {
if (currentChar + 1 == '>') {
_pos++;
_pos++;
yield return new Token(TokenType.MultiLineCommentEnd, "#>");
}
else {
_pos++;
yield return new Token(TokenType.Comment, "#");
}
}
else {
_pos++;
yield return new Token(TokenType.Comment, "#");
}
break;
}
case '{':
{
_pos++;
yield return new Token(TokenType.OpenBrace, "{");
break;
}
case '}':
{
_pos++;
yield return new Token(TokenType.CloseBrace, "}");
break;
}
case '[':
{
_pos++;
yield return new Token(TokenType.OpenBrace, "[");
break;
}
case ']':
{
_pos++;
yield return new Token(TokenType.OpenBrace, "]");
break;
}
case '(':
{
_pos++;
yield return new Token(TokenType.OpenBrace, "(");
break;
}
case ')':
{
_pos++;
yield return new Token(TokenType.OpenBrace, ")");
break;
}
case '<':
{
if (currentChar + 1 < _input.Length) {
if (currentChar + 1 == '#') {
_pos++;
_pos++;
yield return new Token(TokenType.MultiLineCommentStart, "<#");
}
else {
_pos++;
}
}
else {
_pos++;
}
break;
}
default:
if (char.IsLetter(currentChar)) {
var identifierBuilder = new StringBuilder();
while (char.IsLetter(currentChar)) {
identifierBuilder.Append(currentChar);
_pos++;
if (_pos >= _input.Length) {
break;
}
currentChar = _input[_pos];
}
yield return new Token(TokenType.Identifier, identifierBuilder.ToString());
}
else if (char.IsDigit(currentChar)) {
var numericBuilder = new StringBuilder();
while (char.IsDigit(currentChar)) {
numericBuilder.Append(currentChar);
_pos++;
if (_pos >= _input.Length) {
break;
}
currentChar = _input[_pos];
}
decimal d;
if (decimal.TryParse(numericBuilder.ToString(), out d)) {
yield return new Token(TokenType.Number, numericBuilder.ToString());
}
}
_pos++;
break;
};
}
}
public TestLexer(string input)
{
_input = input;
_pos = 0;
}
}

Input must be equal to one of 5 different string values

User input must be equal to one of 5 different strings, if not the user must input again, until the input is equal to one of the 5 strings.
I wrote some code, it works the way it should if the first entered input is equal to one of the 5 strings, if it is not, the program is stuck in an endless loop.
novaDrzava.PrevladujocaVera = Console.ReadLine();
var vera = novaDrzava.PrevladujocaVera;
var prvacrkaVera = vera.Substring(0, 1);
var ostaloVera = vera.Substring(1, vera.Length - 1);
prvacrkaVera = prvacrkaVera.ToUpper();
ostaloVera = ostaloVera.ToLower();
vera = prvacrkaVera + ostaloVera;
while (true)
{
if(vera == "Krščanstvo")
{
break;
}
if (vera == "Krscanstvo")
{
break;
}
if (vera == "Hinduizem")
{
break;
}
if (vera == "Islam")
{
break;
}
if (vera == "Budizem")
{
break;
}
Console.WriteLine("Vnesite ustrezno vero");
vera = Console.ReadLine();
vera = prvacrkaVera + ostaloVera;
}
I can't fully read your code since the identifiers aren't in English. But, given the rest of your question, I think this might be what you want:
var words = new List<string>
{
"Krščanstvo",
"Krscanstvo",
"Hinduizem",
"Islam",
"Budizem"
};
while (true)
{
var input = Console.ReadLine();
if (words.Contains(input, StringComparer.InvariantCultureIgnoreCase))
break;
Console.WriteLine("Invalid selection. Please try again");
}
You forgot to re-assign the values of prvacrkaVera and ostaloVera in the loop
while (true)
{
if(vera == "Krščanstvo")
{
break;
}
if (vera == "Krscanstvo")
{
break;
}
if (vera == "Hinduizem")
{
break;
}
if (vera == "Islam")
{
break;
}
if (vera == "Budizem")
{
break;
}
Console.WriteLine("Vnesite ustrezno vero");
vera = Console.ReadLine();
prvacrkaVera = vera.Substring(0, 1);
ostaloVera = vera.Substring(1, vera.Length - 1);
prvacrkaVera = prvacrkaVera.ToUpper();
ostaloVera = ostaloVera.ToLower();
vera = prvacrkaVera + ostaloVera;
}
Use a switch statement so you can easily detect when other values are entered
while (true)
{
switch(vera)
{
case "Krscanstvo" :
break;
case "Krščanstvo" :
break;
case "Hinduizem" :
break;
case "Islam" :
break;
case "Budizem" :
break;
default :
break; //exit while loop
break;
}
}

Trying to make a switch in a iqueryable any

I have five columns Cc1, Cc2, Cc3...
And I have the following switch statement in the "Any" to check in the columns based on the ccLevel, but the test1 table has 32 million rows and it takes forever to get them, is there a better way to make it faster?
if (_db.Test1.Any(x => CCLevels(x, ccLevel) == cCValue.CcCode))
{
some Message...
}
if (_db.Test2.Any(x => CCLevels(x, ccLevel) == cCValue.CcCode))
{
some Message...
}
private string CCLevels<T>(T x, string ccLevel) where T : IccLevels
{
string level = null;
switch (ccLevel)
{
case "1":
level = x.Cc1;
break;
case "2":
level = x.Cc2;
break;
case "3":
level = x.Cc3;
break;
case "4":
level = x.Cc4;
break;
case "5":
level = x.Cc5;
break;
}
return level;
}
When I make it like the following it takes a second,
if (_db.Test1.Any(x => x.Cc1 == cCValue.CcCode))
{
some Message...
}
if (_db.Test1.Any(x => x.Cc2 == cCValue.CcCode))
{
some Message...
}

multiple string comparing in switch

have a requirement in C# switch in string compare.
string result = getResponse();
switch (result)
{
case "S0": ret = "true";
break;
case "S1": ret = "fail";
break;
// ? can be any digit number, ex, M:0, M:100, M:1000
case "M:?": ret = result;
break;
default: ret = "wrong";
break;
}
how to make the switch statement in "M:?" case?
If you are using C# 7, you can use switch pattern matching.
string ret = string.Empty;
string result = getResponse();
switch (result)
{
case "S0":
ret = "true";
break;
case "S1":
ret = "fail";
break;
case var val when new Regex(#"^M:\d+").IsMatch(val):
ret = val;
break;
default:
ret = "wrong";
break;
}
As #KingKing commented in the question that many devs does not have luxury of using C# 7, at that time you can use following code :
string result = getResponse();
switch (Regex.IsMatch(result, #"^M:\d+") ? "M:XXX" : result)
{
case "S0":
ret = "true";
break;
case "S1":
ret = "fail";
break;
case "M:XXX": // make it unique so that it will not collide with other case statement and update this value in ternary condition accordingly
ret = result;
break;
default:
ret = "wrong";
break;
}
Another option instead of using switch pattern matching is to handle more complex case in the default bloc with if statements like so
string ret = string.Empty;
string result = getResponse();
switch (result)
{
case "S0":
ret = "true";
break;
case "S1":
ret = "fail";
break;
default:
Regex rgx = new Regex(#"^M:\d+");
if (rgx.IsMatch(result))
{
ret = result;
}
else {
ret = "wrong";
}
break;
}
try with pattern matching :-
public string Convert(string result)
{
switch (result)
{
case "S0": return "true";
case "S1": return "fail";
case var m when Regex.IsMatch(m, #"^M:\d+$"): return m;
default: return "wrong";
}
}
if you are using an older C# without pattern matching, move your clause to before the switch
public string Convert(string result)
{
if(Regex.IsMatch(result, #"^M:\d+$")) return result;
switch (result)
{
case "S0": return "true";
case "S1": return "fail";
default: return "wrong";
}
How about using LINQ:
var switches = new Func<string, string>[]
{
x => x == "S0" ? "true" : null,
x => x == "S1" ? "fail" : null,
x =>
{
var match = Regex.Match(x, #"^M:(\d+)");
if (match.Success)
return match.Groups[1].Captures[0].Value;
return null;
},
x => "wrong",
};
string result = "M:47";
string ret = switches.Select(s => s(result)).Where(r => r != null).First();
That gives me "47" for ret.

Escape quotes for interpolated string

I have a program that generates C# from bits of C# stored in an XML file. If I have a snippet like:
foo {bar}
I need to transform that into an interpolated string, like this:
$#"foo {bar}"
The problem is that, if I have quotes outside a placeholder, e.g.:
"foo" {bar}
I need to double those:
$#"""foo"" {bar}"
but ignore quotes inside placeholders:
foo {"bar"}
should produce:
$#"foo {"bar"}"
Also, need to look out for doubled braces:
foo {{"bar"}}
should produce:
$#"foo {{""bar""}}"
And perhaps the trickiest of all, if the placeholder is preceded and/or followed by an even number of braces:
foo {{{"bar"}}}
should produce:
$#"foo {{{"bar"}}}"
In short, if there's a placeholder then ignore everything inside. For the rest of the text, double quotes.
Can this be accomplished using regular expressions? If not, what alternatives do I have?
You will need at least 2 steps:
Add quotes inside the expression:
"(?=[^}]*(?:}})*[^}]*$)|(?<=^[^{]*(?:{{)*)" =>
replace with ""
See demo
Enclose in $#"..." with string.Format("$#\"{0}\"", str);
Here is an IDEONE demo
var s = "\"foo\" {bar}";
var rx = new Regex(#"(?<!(?<!{){[^{}]*)""(?![^{}]*}(?!}))");
Console.WriteLine(string.Format("$#\"{0}\"",rx.Replace(s,"\"\"")));
And another demo here
This cannot be done with regular expressions. Knowing when a placeholder starts is easy, knowing when it ends is the hard part, since a placeholder can hold almost any C# expression, so you have to keep track of blocks ({}) and literals (strings, chars, comments) because any brace in a literal is not significant.
This is the code I came up with:
enum ParsingMode {
Text,
Code,
InterpolatedString,
InterpolatedVerbatimString,
String,
VerbatimString,
Char,
MultilineComment
}
public static string EscapeValueTemplate(string valueTemplate) {
if (valueTemplate == null) throw new ArgumentNullException(nameof(valueTemplate));
var quoteIndexes = new List<int>();
var modeStack = new Stack<ParsingMode>();
modeStack.Push(ParsingMode.Text);
Func<ParsingMode> currentMode = () => modeStack.Peek();
for (int i = 0; i < valueTemplate.Length; i++) {
char c = valueTemplate[i];
Func<char?> nextChar = () =>
i + 1 < valueTemplate.Length ? valueTemplate[i + 1]
: default(char?);
switch (currentMode()) {
case ParsingMode.Code:
switch (c) {
case '{':
modeStack.Push(ParsingMode.Code);
break;
case '}':
modeStack.Pop();
break;
case '\'':
modeStack.Push(ParsingMode.Char);
break;
case '"':
ParsingMode stringMode = ParsingMode.String;
switch (valueTemplate[i - 1]) {
case '#':
if (i - 2 >= 0 && valueTemplate[i - 2] == '$') {
stringMode = ParsingMode.InterpolatedVerbatimString;
} else {
stringMode = ParsingMode.VerbatimString;
}
break;
case '$':
stringMode = ParsingMode.InterpolatedString;
break;
}
modeStack.Push(stringMode);
break;
case '/':
if (nextChar() == '*') {
modeStack.Push(ParsingMode.MultilineComment);
i++;
}
break;
}
break;
case ParsingMode.Text:
case ParsingMode.InterpolatedString:
case ParsingMode.InterpolatedVerbatimString:
switch (c) {
case '{':
if (nextChar() == '{') {
i++;
} else {
modeStack.Push(ParsingMode.Code);
}
break;
case '"':
switch (currentMode()) {
case ParsingMode.Text:
quoteIndexes.Add(i);
break;
case ParsingMode.InterpolatedString:
modeStack.Pop();
break;
case ParsingMode.InterpolatedVerbatimString:
if (nextChar() == '"') {
i++;
} else {
modeStack.Pop();
}
break;
}
break;
case '\\':
if (currentMode() == ParsingMode.InterpolatedString) {
i++;
}
break;
}
break;
case ParsingMode.String:
switch (c) {
case '\\':
i++;
break;
case '"':
modeStack.Pop();
break;
}
break;
case ParsingMode.VerbatimString:
if (c == '"') {
if (nextChar() == '"') {
i++;
} else {
modeStack.Pop();
}
}
break;
case ParsingMode.Char:
switch (c) {
case '\\':
i++;
break;
case '\'':
modeStack.Pop();
break;
}
break;
case ParsingMode.MultilineComment:
if (c == '*') {
if (nextChar() == '/') {
modeStack.Pop();
i++;
}
}
break;
}
}
var sb = new StringBuilder(valueTemplate, valueTemplate.Length + quoteIndexes.Count);
for (int i = 0; i < quoteIndexes.Count; i++) {
sb.Insert(quoteIndexes[i] + i, '"');
}
return sb.ToString();
}

Categories

Resources