Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 7 years ago.
Improve this question
What is the best alternative for a if --else if --block that contains many if statements.
code:
string word="";
if(letter=='a')
{
// do some action
call(a);
}
else if (letter=='b')
{
call(b)
}
else if (letter=='c')
{
call(c)
}
else if (letter=='d')
{
// do some action
call(d)
}
else if (letter=='e')
{
// do some action
call(e)
}
................
..............
else if (letter=='z')
{
// do some action
call(z)
}
If there are many if-else statements what is the best way to find a solution for such a scenario. Is there a way to effectively design such a scenario using classes/objects?
I am sure many of us would have faced such problems like this during design/coding. Is there a effective way to handle such a situation?
NO SWITCH STATEMENTS PLEASE. AN EFFECTIVE DESIGN ALGORITHM USING C# OBJECTS WOULD BE THE BEST BET.
In C# the most direct translation is a switch statement. While switch is not strictly speaking an object-oriented construct, char is not a proper object in C# either.
switch(letter)
{
case 'a':
call(a);
break;
case 'b':
call(b);
break;
// and so on
}
If the parameter is not a simple value type but rather an object, use a virtual method instead of an explicit control structure. This is the true "object oriented" way to do it: in Smalltalk, ifTrue:, ifFalse: and ifTrue:ifFalse: are methods on Boolean taking code blocks as parameters! C# makes this rather verbose, though.
static class Example {
static void Sample(ISpeaker input) {
input.Speak(); // this call acts like a control structure
}
}
interface ISpeaker {
void Speak();
}
class Cat : ISpeaker {
public void Speak() {
Console.WriteLine("Meow");
}
}
class Dog : ISpeaker {
public void Speak() {
Console.WriteLine("Woof");
}
}
If you are stuck with a simple type, another approach is an explicit dispatch table.
static readonly Dictionary<char, Action> dispatch
= new Dictionary<char, Action> {
{ 'a', () => call(a) },
{ 'b', () => call(b) },
};
static void Process(char letter) {
dispatch[letter]();
}
If your conditions are too complex for a Dictionary-based dispatch table, you can use a List-based linear dispatch table which more closely mirrors the behavior of else-if chains:
static List<KeyValuePair<Func<char, bool>, Action>> dispatch
= new List<KeyValuePair<Func<char, bool>, Action>>() {
{ x => x == 'a', () => call(a) },
{ x => x == 'b', () => call(b) },
{ x => true, () => callDefault() },
};
static void Process(char letter) {
dispatch.First(kvp => kvp.Key(letter)).Value();
}
You can do the following:
private Dictionary<char, Action> _dic =
new Dictionary<char, Action>
{
{'a', (Action)a},
{'b', (Action)b},
...
};
And then
var action = this._dic.TryGetValue(letter);
if (action == null)
{
// this is like default case - no key matched the letter
}
else
{
// call the action associated with the letter
action();
}
https://msdn.microsoft.com/en-us/library/06tc147t.aspx
Do you mean a switch? This is effectivly like a large list of else-ifs
Use switch as an alternative to if...else.
switch offers more readability of your code and is more easy to understand rather that if else where, if you are nesting heavily, it might get difficult to understand and read code.
Also, switch is slightly better on the performance side when compared to if...else.
Hope this helps.
Technically, you picked a more complex way to express a switch statement. Switch statements, in turn, may be considered a "code smell".
If I understand your example correctly, you really only want to vary a parameter on a method call based on the value of some variable. There might not be any good way to improve upon writing your code as switch statement, but maybe using a Dictionary to look up the parameter based on the letter value is an option to consider.
You can use a switch statement.
switch (letter)
{
case 'a':
case(a);
break;
case 'b':
case(b);
break;
...
case 'z':
case(z);
break;
default:
Assert.Fail(letter.ToString() + " was an unexpected value");
break;
}
Use a switch statement:
switch(value)
{
case value == "X":
// handle
break;
case ...
break;
default:
// Doesn't match any case above
break:
}
Related
I'm currently working on a .NET 4.7.1 application. I have an If-statement to check the data type and call an handler method accordingly.
My current If statement looks like this:
// object msg = MyHelper.Deserialize(xmlString);
if (msg is Tomato) Handle_Tomato((Tomato)msg);
if (msg is Apple) Handle_Apple((Apple)msg);
if (msg is Banana) Handle_Banana((Banana)msg);
if (msg is Orange) Handle_Orange((Orange)msg);
msg is basically an object deserialized from a string.
I was wondering, if there is a better way to write my if statements?
Thank you very much!
As Sweeper mentions in the comments, from C# 7.0 you can use the The is type pattern expression
if (msg is Tomato tomato) Handle_Tomato(tomato);
You could also use pattern matching with a switch statement (Type pattern) since C# 7.0
The type pattern enables concise type evaluation and conversion. When
used with the switch statement to perform pattern matching, it tests
whether an expression can be converted to a specified type and, if it
can be, casts it to a variable of that type.
switch(msg)
{
case Tomato tomato : Handle_Tomato(tomato); break;
case Apple apple : Handle_Apple(apple); break;
...
}
I'd strongly suggest not to do such checks. What if in the future there are dozens of different types? Your if statement will increase and be unmaintainable. What if the type changes? You'd have to change all the if statements as well.
You could solve this by using an interface. You already have the classes.
interface IHandler
{
void Execute();
}
class Orange : IHandler
{
public void Execute()
{
// do your orange stuff
}
}
class Tomato : IHandler
{
public void Execute()
{
// do your tomato stuff
}
}
It can be called like this.
if (msg is IHandler) ((IHandler)msg).Execute();
I think the easiest would be to use a switch/case
switch (msg)
{
case Tomato t:
Handle_Tomato(t);
break;
case Apple a:
Handle_Apple(a);
break;
case Banana b:
Handle_Banana(b);
break;
case Orange o:
Handle_Orange(o);
break;
}
Use a dictionary. I foresee your if will explode with new cases in future, generally speaking, walls of if and large switch statements are bad code. In a similar situation I created something like this:
private static readonly Dictionary<RuntimeTypeHandle, Action<object>> handleMsgImplementations = new Dictionary<RuntimeTypeHandle, Action<object>>
{
{ typeof(Tomato).TypeHandle, x => Handle_Tomato((Tomato)x) },
// etc...
};
// Then instead of if, use this (prepare a catch for Invalid Key or use a TryGetValue)
handleMsgImplementations[msg.GetType().TypeHandle](msg);
I get TypeHandle because I like to use a value type for the key.
EDIT: #TheGeneral answer is the best, also, the C# compiler creates a dictionary under the hood when the amount cases starts to damage performance. I keep my answer because I believe adds value.
This question already has answers here:
Switch case in C# - a constant value is expected
(9 answers)
Closed 5 years ago.
I'm having a problem here.
void Sre_Reconhecimento(object sender, SpeechRecognizedEventArgs e)
{
string text = System.IO.File.ReadAllText(#"C:\Users\ADMIN25\Desktop\testing.txt");
string[] words = text.Split(',');
switch (e.Result.Text)
{
case words[0]:
MessageBox.Show("works!");
break;
case words[1]:
MessageBox.Show("works too!");
break;
}
}
When I'm trying to run the program, I get this error: A constant value is expected.
How can I fix it without using if/elseif case?
You should do this with if / else.
However, if for some reason you really want to use a switch, you can sort of do it with pattern maching.
e.g.
void Main()
{
string[] words = {"Foo", "Bar", "Quax"};
var word = "Bar";
switch(word)
{
case string w when w == words[0]:
MessageBox.Show($"word was {words[0]}");
break;
case string w when w == words[1]:
MessageBox.Show($"word was {words[1]}");
break;
}
}
Really though, use if / else here. I don't think switch is appropriate for this type of use case.
You cant use a switch statement dynamically like this, because its expects a constant value at compile time
However
You can use a collection of if statements,
You could also use a dictionary of Action
Exmaple
dict = new Dictionary<string, Action>()
{
{"Standard", CreateStudySummaryView},
{"By Group", CreateStudySummaryByGroupView},
{"By Group/Time", CreateViewGroupByHour}
};
dict[value].Invoke();
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 6 years ago.
Improve this question
i'm making simple name generator, and it's working like that: I got an array with name values it's 4 elements, and i'm using random class to pick specific name from array, and next i'm using switch case to validate which one is picked and print it to console.
But, it's only 4 element, but what when i'll try to make 100 elements 4example? I've tried to make switch case in for loop to increment everything in one case, but it turns out that case index should be const. Well, is there any other possible way to make switch case more flexible, and smaller?
Here's code for intersed http://pastebin.com/bbCxLtRq
There is no switch needed:
if (NameIndex >= 0 && NameIndex <= 3)
{
return Name[NameIndex];
}
return null;
With more complex examples, you can use return to get rid of break.
Instead of
switch (NameIndex)
{
case 0:
name = Name[0];
break;
case 1:
name = Name[1];
break;
case 2:
name = Name[2];
break;
case 3:
name = Name[3];
break;
}
return name;
write
switch (NameIndex)
{
case 0:
return Name[0];
case 1:
return Name[1];
case 2:
return Name[2];
case 3:
return Name[3];
}
return null;
As mentioned in the comments, there is NO need for Switch statement to achieve this goal - refer to the following code snippet as an example:
public class Generate
{
static string[] Name = new string[] { "Mariusz", "Janusz", "Bogdan", "Zbigniew" };
static Random random = new Random();
public static string NameGen()
{
return Name[(int) random.Next(3)];
}
}
In case you really need to use Switch statement (for some reason, may be just for didactic purpose), then there is a way to simplify it like shown in the following snippet:
switch (NameIndex)
{
case 0:
case 1:
case 2:
case 3:
return Name[NameIndex];
}
Hope this may help
Make your methods independents of a fixed length:
public static string NameGen()
{
int index = random.Next(Names.Length);
return Names[index];
}
public static string SurnameGen()
{
int index = random.Next(Surnames.Length);
return Surnames[index];
}
Im quite new to C# and was wondering if it's possible to pass something to a function which is undefined / different each time, like the example below ;
string stringexam = "string"
or
int intexam = 5;
or
bool exam = false;
etc..
Myfunction(stringexam);
Myfunction(intexam);
Myfunction(exam);
public static void MyFunction(accepteverything) {
//DO SOMETHING
}
How could something like this be achieved ?
I need this because then I could use something like this in my code :
MyFunction(1,"ok example 1");
MyFunction(2, 22);
MyFunction(3, false);
Then I could continue in the MyFunction :
MyFunction(int method, accepteverything?!)
{
if(method == 1) {
ContinueExample1(string accepteverything); // CALLS FUNCTION CONTINUEEXAMPLE1 WHICH NEEDS A STRING AS PARAMETER
}
if(method == 2) {
ContinueExample2(int accepteverything); // CALLS FUNCTION CONTINUEEXAMPLE2 WHICH NEEDS A INT AS PARAMETER
}
if(method == 3) {
ContinueExample3(bool accepteverything);
}
}
You can do it with method overloads, the same named function but with different parameter types.
void MyFunction(string accepteverything)
{
ContinueExample1(accepteverything);
}
void MyFunction(int accepteverything)
{
ContinueExample2(accepteverything);
}
void MyFunction(bool accepteverything)
{
ContinueExample3(accepteverything);
}
This lets you do
string stringexam = "string"
int intexam = 5;
bool exam = false;
MyFunction(stringexam);
MyFunction(intexam);
MyFunction(exam);
You can also use Generic functions. This avoids boxing/Unboxing too
public void MyFunction<T>(int method, T acceptEverything)
{
switch(method)
{
case 1: ContinueExample1(acceptEverything as string); //String parameter
break;
case 2: ContineExample2(Convert.ToInt32(acceptEverything)); //int parameter
break;
// etc.
}
}
Call like this
MyFunction(1,stringexam);
MyFunction(2,intexam);
If the behavior of the method is the same no matter what type is passed in, you could pretty easily make the method:
public void MyFunction(int method, object acceptEverything)
{
switch(method)
{
case 1: ContinueExample1(acceptEverything as string);
break;
case 2: ContineExample2(acceptEverything as int);
break;
// etc.
}
}
Unfortunately that is going to introduce a lot of boxing and unboxing.
Sure, you could. But you probably want to rethink the way you're going about things. Wanting to reduce the code you have to write is good.
Bill Gates — 'I choose a lazy person to do a hard job. Because a lazy person will find an easy way to do it.'
But it's not always necessary, and can introduce unneeded complexity to something that otherwise is simple and self-explanatory.
Think about what's going on in your code. You have an exam which you want to do something with. Presumably you're concerned that there might be more than one way to identify a given exam for different users. But, whatever it is you want to do is probably not going to change. So, let's attack from that angle: we need to be able to identify an exam given some unknown parameter.
public Exam FindExamFromAnything(object input)
{
int examID = 0;
if (int.TryParse(input.ToString(), out examID))
{
return GetExamFromID(examID);
}
else
{
return GetExamFromName(input.ToString());
}
}
public Exam GetExamFromID(int ID)
{
// get the Exam with the right ID from a database or something
}
public Exam GetExamFromName(string examName)
{
// get the Exam with the right name from a database
}
Now you've got a method that you can pass whatever, and you'll get back the thing you were looking for. Great!
Except... two years from now somebody has a list of students that took a given exam, and tries to use your method:
List<string> students = new List<string> {"Alice","Bob"};
var exam = FindExamFromAnything(students); // nope!
Doesn't work. But how would he know? There's nothing in the signature that specifies what to use as the object. Now he's got to locate your source code, or use trial and error, to figure out how to use your API. Your documentation might explain that it only takes an int or a string, but...
Instead, it's not really that much more work to write a second method. As Scott Chamberlain points out you can overload a method name to take different parameters. A better solution for this implementation is to get more specific; I'm partial to methods like above exposed, that is, expose your GetExamFromString and GetExamFromID and whatever else you need, so they are self explanatory.
Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 9 years ago.
Improve this question
Consider this code:
if (results.Contains(14))
{
//anything
}
else if (results.Contains(15))
{
//anything
}
else if (results.Contains(16))
{
//anything
}
I want write this code with switch case :
switch (results)
{
case results.Contains(14):
}
But we can't write this in C#.
What is the clear way for write the above code, knowing that results is a long[]?
What's wrong with this:
if (results.Contains(14) || results.Contains(15) || results.Contains(16))
{
new Exception("anything");
}
since it is probably in a string that has that number one solution would be to use a regular expression.
var m = System.Text.RegularExpressions.Regex.Matches(results, #"\d{1,2}")[0];
throw new Exception(m);
(NOTE: I did this in notepad so it might require a small tweak)
You will have to probably play with the match syntax as this is only good for 1-2 numbers. in a string.
What are you really trying to do?
The following should work, but I am not sure if that's what you had in mind:
int[] values = {14, 15, 16};
foreach (var n in values) {
if(result.Contains(n))
throw new Exception(n.ToString())
}
-- EDIT: the question has changed considerably so here's an update --
I would probably use plain if-else but if you have many options or complex logic (e.g. not just results.Contains()), sometimes it is better to choose tables:
int[] results = {13, 14, 15};
action_map = new Dictionary<int, Action>();
action_map[14] = () => Console.Out.WriteLine("14");
action_map[15] = () => Console.Out.WriteLine("15");
action_map[16] = () => { throw new InvalidOperationException(); };
action_map[0] = () => {}; // NOP, default case - executed if no match found
var action_key = dict.Keys.FirstOrDefault(k => results.Contains(k));
action_map[action_key]();
In real code, I would probably wrap it into a class:
var table = new FnTable();
table.Add(14, () => Console.Out.WriteLine("14"));
table.Add(15, () => Console.Out.WriteLine("15"));
table.Add(16, () => { throw new InvalidOperationException(); });
int[] results = {13, 14, 15};
table.ExecuteFirstFrom(results);
Usually a clear way to replace if/switch statements is to use polymorphism. However, in the example you've provided the if statements are so trivial, that they can be replaced by a simple algorithm which calculates the contents of the exception, as stated in Robert Snyder's answer.
I like approach with action dictionaries
var swticher = new Dictionary<long, Func<Exception>>()
{
{15,()=>new Exception("15")},
{14,()=>new Exception("14")}
};
throw swticher[14].Invoke();
Of course more complex examples will show power of this approach :)
Why to use dictionaries instead of switches: https://stackoverflow.com/a/11617459/1714342
Abstract:
The short answer is that the switch statement executes linearly, while
the dictionary executes logarithmically.
You can use a switch statement inside a foreach:
long[] results = new long[] { 15, 14, 16 };
foreach (long v in results)
{
switch (v)
{
case 14:
// anything
break;
case 15:
// anything
break;
case 16:
// anything
break;
}
}
And to better match with your question, you should order the array first and get out the foreach after a match:
long[] results = new long[] { 15, 14, 16 };
Array.Sort(results);
foreach (long v in results)
{
switch (v)
{
case 14:
// anything
break;
case 15:
// anything
break;
case 16:
// anything
break;
default:
continue; // continue the foreach loop
}
break; // break the foreach loop because we had a valid match
}
switch (C# Reference):
Each case label specifies a constant value.
In your expected sample code, results.Contains(14) is not a constant value, so the syntax will not be valid.
I would not actually recommend to do it this way, but if you're really into switch statements...
long? CheckSpecialNumbers(long[] res)
{
var specialNumbers = new List<long>() {14, 15, 16};
var inters= specialNumbers.Intersect(res);
return inters.Count() > 0 ? (long?)inters.First() : null;
}
then you could do:
long? res = CheckSpecialNumbers(results);
switch (res)
{
case 14:
Console.WriteLine(14);
break;
case 15:
Console.WriteLine(15);
break;
case 16:
Console.WriteLine(16);
break;
}
I want write this code with switch case
A switch-case statement is used to branch the execution path according to the value of a given variable. The OP wants to branch according to the value of a Boolean expression, specifically, the return value of Contains. This can only be done using an if-else statement. Writing switch (results) doesn't make sense, since results is an array of integers.