Alternative for switch that only calls methods based on cases values - c#

Is there a possible way to write the next switch in some shorter, readable code?
switch (SomeValue)
{
case "001": return DoMethod1(); break;
case "002": return DoMethod2(); break;
//etc..
}
I was thinking in some way like
Dictionary<string, Func<int>> MethodsByValue = new Dictionary<string, Func<int>>()
{
{ "001", DoMethod1 },
{ "002", DoMethod2 },
}
and call this by doing
return MethodsByValue[SomeValue]();
But is this even possible? Or am I thinking way to far out of the box. I couldn't find anyting like this but then again, I don't know the keywords for this if it is possible.
EDIT: To answer the request of Lasse V. Karlsen:
This is how the code is in my project. Changed names at some places cause original names doesn't matter cause it is in my mother language.
public string GetRecord420(Dictionary<DataClass, object> dictionaryName)
{
// some code here
}
public string GetRecord421(Dictionary<DataClass, object> dictionaryName)
{
// some code here
}
//(Temperary) solution with the switch statement in a wrapper:
public string GetRecordByString(string s, Dictionary<DataClass, object> dictionaryName)
{
switch (s)
{
case "320": return GetRecord420(dictionaryName);
case "321": return GetRecord421(dictionaryName);
default: return String.Empty;
}
}
//How I hoped it could be, with a mapping dictionary.
public Dictionary<string, Func<string, Dictionary<DataClass, object>>> MethodByString =
new Dictionary<string, Func<string, Dictionary<DataClass, object>>>()
{
{ "320", GetRecord420 },
{ "321", GetRecord421 },
}
DataClass is an Entity class, which stores some column data (column name, column type, etc.).
I tried the dictionary part, but it gives me the error: Cannot convert from method group to System.Func<...>.
Changing to () => GetRecord420 gives me the error: Cannot convert lambda to delegate type System.Func<...> because some of the return types in the block are not implicitly convertible to the delegate return type.

There must be an error with your method definitions,
class Program
{
static void Main()
{
var methods = new Dictionary<string, Func<int>>
{
{ "001", DoMethod1 }
};
}
static int DoMethod1()
{
return 1;
}
}
is perfectly valid syntax.
but, this is not better than switch for 1 compelling and 1 subjective reason.
If you are comparing against constants or literals then you should use switch. This enables the compiler to peform compile time optimizations without additional analysis.
More subjectively, the dictionary/lookup approach is no shorter and I find it harder to read. However, it would be useful in situations where your comparison terms vary at runtime.
If you want avoid rewriting the switch factor it into a function. Say,
Func<int> MethodsByValue(string value)
{
switch(value)
{
case "001":
return DoMethod1;
default:
return DoMethod2;
}
}
Either way,
Rather than using some arbritary strings to enumerate your methods, why not use an enum? Then you will get additional performance and readability benefits.

In general a good alternative for switch would be using State Design Pattern other good alternative is Strategy Pattern. It will make your code more extensible and is more object oriented approach.

You can shorten what you have simply by removing the redundant breaks, and if it happens that two cases should call the same method then you can fall through:
switch (SomeValue) {
case "001": return DoMethod1();
case "002": return DoMethod2();
case "003":
case "004": return DoMethod34();
//etc..
}
As for your pseudo suggestion, and the other answer advocating it, I don't see how this is any short or more concise. However, in usage is could reduce code and be clear, such as, briefly:
Func<int> GetMethod(string key) {
return MethodsByValue[key];
}
Func<int> method = GetMethod("001");
method();

I use a Mapping extension for that. This way yoy can use the following syntax:
return SomeValue
.Map("001", DoMethod1)
.Map("002", DoMethod2)
//etc
This makes it also possible to do this:
return SomeValue
.Map(1, DoMethod1)
.Map(2, DoMethod2)
.Map(x => x < 0, DoMethod3)
.Map(x => x > 5 && x < 10, DoMethod4)
.Else(4); // a simple value of a method

Related

Replace switch statements for child class type

There is a method that accepts 2 parameters:
int selectedClass;
int selectedFunction;
Next, there goes 2 switch statements. First of all, it determines child class type using enum:
ParentClass p;
switch(selectedClass){
case (int)ClassTypes.A:
p = new classA();
break;
case (int)ClassTypes.B:
p = new classB();
break;
case (int)ClassTypes.C:
p = new classC();
break;
}
And it goes on an on for like 50 more statements. Furthermore, there is another switch statement that determines a function:
string result;
switch(selectedFunction){
case (int)FunctionTypes.Func1:
result = p.function1();
break;
case (int)FunctionTypes.Func2:
result = p.function2();
break;
case (int)FunctionTypes.Func3:
result = p.function3();
break;
}
I did use the search, there are a lot of examples of improving the second switch statement, but not the first one. The 1st question is: how do we determine both child class and function with no switch statements?
2nd: In js I would do something like that:
functionsArray[selectedClass][selectedFunction]();
Is it possible to implement similar kind of mapping in c#?
Update #1:
I have replaced the 1st switch with the following code:
public static Dictionary<ClassTypes, Type> typeDict = new Dictionary<ClassTypes, Type>()
{
{ ClassTypes.A , typeof(classA) },
{ ClassTypes.B , typeof(classB) },
{ ClassTypes.C , typeof(classC) }
};
ParentClass p = (ParentClass)Activator.CreateInstance(typeDict[selectedClass]);
I can't say I understand the logic that lead you to pick this strange design, but I can think of at least two ways to improve it, providing all the functions you are calling are implemented in the base class (and overriden when needed in the derived classes, of course).
Both solutions are only relevant in case all classes provides a parameter-less constructor and parameter-less functions, and executing the functions does not require further initialization:
The first solution would require you to change the method signature, and force the calling method to know the types of the classes so you might not be able to implement it but it involves far less code.
ExecuteMethod<TClass>(Func<TClass, string> func) where T: BaseClass, new()
(
return func(new T());
)
And you call it like this:
var result = ExecuteMethod<ClassA>(a => a.Function1);
The second solution
This might be more suitable for your needs:
You will need to create two dictionaries and populate them, like this:
private Dictionary<int, Func<ParentClass>> constructors = new Dictionary<int, Func<ParentClass>>()
{
{1, () => new ClassA()},
{2, () => new ClassB()}
// more of the same
};
private Dictionary<int, Func<ParentClass, string>> methods = new Dictionary<int, Func<ParentClass, string>>()
{
{1, i => i.function1},
{2, i => i.function2}
// more of the same
};
Then your method can still take two ints and return a string:
string DoSomething(int classType, int function)
{
var instance = constructors[classType].Invoke();
return methods[function].Invoke(instance);
}
Please note that the code is written directly here and not tested, so I might have missed a thing or two, but this is the general idea.
I did some changes to your original code, I changed the input parameters to strings, assuming you can directly take names as input. And then instantiating using the first method and invoking using the second. I have added an overload if you want to continue to use the Enum.
string selectedClass;
string selectedFunction;
public object GetClassInstanceFromName(string name)
{
object type = Type.GetType($"{this.GetType().Namespace}.{name}";
return Activator.CreateInstance((Type)type);
}
public string InVokefunctionByName(object instance,string methName)
{
return instance.GetType().GetMethod(methName).Invoke(instance, null) as string;
}
//Overload if you want to continue to use your enum
public object GetClassInstanceFromName(ClassTypes name)
{
return
Activator.CreateInstance(Assembly.GetExecutingAssembly().FullName,
"class" +name.ToString());
}
private void Test()
{
object a = GetClassInstanceFromName(selectedClass);
Console.WriteLine(InVokefunctionByName(a, selectedFunction));
Console.ReadKey();
}
Also switching to a better design will always be recommended way.

C# replacing huge if-else statement

let's say i have Item object witch mostly holds enum properties like this
public enum Shape
{
square = 1,
trangle = 2,
any = 3
}
public enum Color
{
blue = 1,
red = 2,
yellow = 3,
green = 4
}
public enum Material
{
glass = 1,
wood = 2,
metal = 3
}
public class Item
{
public Shape ItemShape { get; set; }
public Color ItemColor { get; set; }
public Material ItemMaterial { get; set; }
}
What am trying to do is depends of combination of whole three properties i need to do some action later;
I was thinking to use if-else combination like:
if(item.ItemShape == Shape.square && item.ItemColor == Color.blue && item.ItemMaterial == Material.glass)
{
//call Action1
}
else if(item.ItemShape == Shape.square && item.ItemColor == Color.blue && item.ItemMaterial == Material.wood)
{
// action2
}
......
Problem is that i have around 16 of combinations, so it will be huge if-else method to resolve what method should i call later.
Maybe is there any other way to replace if-else statements more readable code, design patter or something more efficient?
I was thinking to combine whole possible states as flag enum values, but not sure if i can create enum value from object property later.
I think your best bet would be to ceate a Dictionary that would map your values to methods.
Now there are several options what could be the key in your dictionary - see below.
Disclaimer
Please also note that a big if statement is only an issue, if it is spread / duplicated across the codebase, and changes frequently - putting things in a dictionary does not really reduce complexity. Having methods in a dictionary also changes the semantics of your code. The first question should be - am I changing the mappings at runtime? Should they really be dynamic?
Dictionary with key ValueTuple struct you could use syntax (Shape, Color, Material) - this is the easiest one. Please note - not the Tuple class, but ValueTuple struct.
Dictionary with key Item class itself, but then you would need to take care about proper equality comparison in Item. You could make Item a struct to get that for free (but with slower performance, that comes from equality comparisons in System.ValueType that uses reflection in general case), or leave it as a class (or struct) and implement IEquatable<Item>, Equals and GetHashCode.
Without proper equality comparison, your dictionary lookup will not work (as suggested by #ckuri)
Use ValueTuple without a dictionary to simply condense your code.
A variation of the State pattern where you have a shared interface / base class for your handler. Handler is a separate class that contains one action for a specific set of values, like AnyBlueGlassHandler : Handler. Each handler checks the If condition, and when true, runs the actions. You could then put the handlers in a List<T> and apply them for an item like handlers.Foreach(x=>x.Handle(item))
The code when Item is the key could look like:
public static class ItemExtensions
{
static Dictionary<Item, Action<Item>>
methods = new Dictionary<Item, Action<Item>>()
{
{ new Item(Shape.any, Color.blue, Material.glass), x=> { /*do something*/ } }
};
public static bool TryApply(this Item item)
{
if (methods.TryGetValue(item, out var action))
{
action(item);
return true;
}
return false;
}
}
the code when ValueTuple is the key could look like
public static class ItemExtensionsUsingValueTuple
{
static Dictionary<(Shape, Color, Material), Action<Item>>
methods = new Dictionary<(Shape, Color, Material), Action<Item>>()
{
{ (Shape.any, Color.blue, Material.glass), x=> { /*do something*/ } }
};
public static bool TryApply(this Item item)
{
if (methods.TryGetValue((item.ItemShape, item.ItemColor, item.ItemMaterial), out var action))
{
action(item);
return true;
}
return false;
}
}
a more condensed version of your code with ifs, could look like:
declare Key property on your Item class
public (Shape, Color, Material) Key => (ItemShape, ItemColor, ItemMaterial);
use more elegant if statement
if ( item.Key == (Shape.any, Color.blue, Material.glass)) { }
It sounds like you want some rule set to check an item against.
I think the simplest form to make this more readable, is to pass the item, the properties of the rule, and the action to a separate method:
public bool RunActionIf(Item item, Shape shape, Color color, Material material, Action action)
{
if(item.ItemShape == shape && item.ItemColor == color && item.ItemMaterial == material)
{
action();
return true;
}
return false;
}
public void RunAction(Item item)
{
var result =
RunActionIf(item, Shape.square, Color.blue, Material.glass, Action1) ||
RunActionIf(item, Shape.square, Color.blue, Material.wood, Action2) ||
/* Implement your whole table like this */;
if(!result)
{
throw new ArgumentException("No matching rule found", nameof(item));
}
}
The main advantage of that method is that it's shorter and with less 'overhead' in the declaration. You can easily see: shape X + color Y + material Z= that action.
Another advantage is that it's easier to implement certain exceptions, for instance by allowing one of the rule parameters to be null to indicate any color, or to use Color.any to support that, although I think it's confusing to have any in the enum with other colors... Anyway, I digress. The point is, if you want to implement that, you have to do that only in one place without having to copy it 16 times.
You could abstract this away a bit further by making such a rule a separate object, which you can put in a list or dictionary, but for a definition like this, it doesn't make it that much more readable, although it does add some benefits of testibility, as well as the possibility to add different kinds of rules, without messing up your clean list again.
Try Dictionary<T>, for instance:
static Dictionary<Tuple<Shape, Color, Material>, Action> s_Actions = new
Dictionary<Tuple<Shape, Color, Material>, Action>() {
{Tuple.Create(Shape.square, Color.blue, Material.glass), () => { ... } },
...
{Tuple.Create(Shape.any, Color.red, Material.metal), () => { ... } },
...
};
private static void RunAction(MyItem item) {
Action action;
// Either exact match or match with Any
if (!s_Actions.TryGetValue(Tuple.Create(item.ItemShape, item.ItemColor, item.ItemMaterial),
out action))
action = s_Actions.FirstOrDefault(pair => pair.Key.Item1 == Color.any &&
pair.Key.Item2 == item.ItemColor &&
pair.Key.Item3 == item.ItemMaterial)
// Execute action if it's found
if (action != null)
action();
}
void RunAction((Shape shape, Color color, Material material) item)
{
switch(item)
{
case var i1 when i1.color == Color.red && i1.shape == Shape.square:
case var i2 when i2.color == Color.blue:
// Do action...
break;
case var i1 when i1.shape == Shape.trangle && i1.material == Material.metal:
// Do action...
break;
default:
// Do action...
break;
}
}
This solution uses Value Tuples, but primarily uses C#7 pattern matching in switch statements.
I don't think it totally solves your problem cleanly, but I think the multi-line cases gives you extra readability over the if statement approach and it's easy to implement.

switch() statement with string.contains() as parameter

I'm somewhat new to C# and I'm trying to create a switch method that returns an ID (int) corresponding to the given filename.
For example:
var fileName = "file-example_MAP_COPY.xml";
var fileTypeId = GetFileTypeId(fileName); // Returns 3310
With the GetFileTypeId method looking something like this:
private GetFileTypeId(string fileName)
{
switch(string.Contains(fileName))
{
case ".xsd":
return 3010;
case "_Gui.xml":
return 3120;
case ".xml":
return 3300;
case "_MAP_COPY.xml":
return 3310;
...
}
}
I cannot trim the actual filename off and only keep the extension since the filename could contain underscores. A file with the name "example_1_MAP_COPY.xml" would be trimmed to "_1_MAP_COPY.xml" if trimmed at first underscore, resulting in a faulty file extension.
An if statement would work here, but since I have 18 different cases I'd like to find another solution than to write 18 if statements.
Is there some way I can go about to do this, either with a switch statement or a dictionary perhaps?
In current C#, you can do:
switch(filename) {
case string s when s.Contains(".xsd"): // or EndsWith, etc
...
}
I'm not saying that's the best approach or that it adds anything over if/else if, but... it works.
There's not much to choose between 18 complex case statements vs 18 if statements; except the if approach doesn't require you to add break; everywhere, and doesn't leak variable declarations between cases.
Personally, I'd use if/else if - or a static array of match/result pairs:
static readonly (string Match, int Result)[] MatchResults = new[] {
(".xsd", 3010),
("_Gui.xml", 3120),
// ...
};
...
foreach(var pair in MatchResults) {
if(filename.Contains(pair.Match)) return pair.Result;
}
You can use a switch indeed, but it seems you are only using the end of the string, so you could use another list type to save the patterns and their outcome:
var l = new []
{ new { Pattern = ".xsd", Value = 3010 }
, new { Pattern = "_MAP_COPY.xml", Value = 3310 }
};
foreach (var p in l)
{
if (filename.EndsWith(p.Pattern))
{
return p.Value;
}
}
// not found
You can use a switch indeed, but it seems you are only using the end of the string, so you could use a dictonary I think is simplier:
private readonly Dictionary<string, int> _ids = new Dictionary<string, int>
{
{".xsd", 3010},
{".xml", 3300},
{"_Gui.xml", 3120},
{"_MAP_COPY.xml", 3310}
};
private int GetFileTypeId(string fileName)
{
var element = _ids.FirstOrDefault(_ => fileName.Contains(_.Key));
return element.Value;
}

Is there a way to shorten the condition if it always compares to the same thing?

I have always found it annoying when I need to write a condition that compares the same item over and over again since I would have the type the item so many times:
string x = textBox1.Text;
if (x == "apple" || x == "orange" || x == "banana" ...)
...
I want something like this (but of course this is not correct syntax):
if (x == "apple" || "orange" || "banana" ...)
Is there a solution other than using an array of the strings?
Your condition says: I'm true if I match any of the predefined values. In other words if I'm an element of a predefined set which is semantically the Contains method:
if (new [] { "apple", "orange", "banana" }.Contains(x))
{
}
Using an array provides much more flexibility in the future. You can extract it out, reuse it, store it, chache it etc. I always use "arrays and loops" when I have to deal with more than 2 known values.
Note: As Scott Chamberlain pointed out in the comments with using HashSet<T>.Contains greatly improves the performace:
var values = new HashSet<string> { "apple", "banana", "orange" };
if (values.Contains(x))
{
}
What about an extension method?
public static class Extensions
{
public static bool IsOneOf<T>(this T input, params T[] possibilites)
{
bool result = possibilites.Contains(input);
return result;
}
}
You could then rewrite your code to look like this:
string input = textBox1.Text;
if(input.IsOneOf("apple", "orange", "banana"))
{
// ....
}
Your best bet (in terms of performance) is to use HashSet
static HashSet<string> Fruits = new HashSet<string> {"apple", "banana", "orange"};
string x = textBox1.Text;
if( Fruits.Contains( x)) {
Once you get beyond three or so possibilities in the if condition, a HashSet will run faster than straight comparison.
You can move duplicated code to the method, which also will explain why this code is duplicated - because it verifies whether something is fruit. It will increase readability and maintainability of your code. Also you will be able to refactor this logic (e.g. turning it into switch statement):
private bool IsFruit(string name)
{
switch(name)
{
case "apple":
case "orange":
...
case "banana":
return true;
default:
return false;
}
}
Usage:
string x = textBox1.Text;
if(IsFruit(x))
...
UPDATE: Better do not use such complex conditions - it's really hard to understand sometimes. You can use Introduce Explaining Variable or Extract Method (as above) refactorings to make your code more clear.
use a switch statement with like so
switch (x)
{
case "apple":
case "orange":
case "banana":
//code
break;
}
You could try a switch statement:
switch (x)
{
case "apple":
case "orange":
case "banana":
//...
break;
}
You can use a switch statement:
switch(x)
{
case "apple":
case "orange":
case "banana":
// "if" code goes here
break;
default:
// "else" code goes here
break;
}
linq solution
var strarray = new string[]
{
"apple",
"orange",
"banana"
};
bool a = strarray.Any( x=> x == textBox1.Text);
if(a)
//CODE
else
//code
try switch case like this
Switch(value)
{
case "apple":
case "orange":
case "banana":....
//code you want
break;
}
I like the extension method solution and have used it before. Here are the methods I have available in my "CommonUtils" library:
public static bool IsIn<T>(this T toFind, IEnumerable<T> collection)
{
return collection.Contains(toFind);
}
public static bool IsIn<T>(this T toFind, ICollection<T> collection)
{
return collection.Contains(toFind);
}
public static bool IsIn<T>(this T toFind, params T[] items)
{
return toFind.IsIn(items.AsEnumerable());
}
Between these three, you can pretty much use any collection, and you can also specify the items as a parameter list.
You could do something like this:
string it = "apple,orange,banana";
if(it.Contains(x))
{
//do work
}
Even simpler:
if("apple,orange,banana".Contains(x))
{
//do work
}

Composing of delegates (functional pitfall)

When trying to use delegates in C# to solve a problem in a functional way, I've come across a pitfall that I want to share resp. for which I would like to hear your suggestions.
Background
I want to fill a grid from a list of objects where the values for single columns are get using delegates (idea borrowed from Philip Pipers ObjectListView control).
Additionally I want to automatically insert columns containing the (numerical) difference between two values.
So my objects having properties FirstValue, SecondValue and ThirdValue I want to have columns with FirstValue, (SecondValue-FirstValue), SecondValue, (ThirdValue-SecondValue), ThirdValue.
I already have adapted an existing grid control to use delegates on an object list, this part works fine.
First attempt
First, I tried something like:
class MyGridClass : DelegateGrid
{
DelegateGrid.ValueGetter lastGetter;
public MyGridClass() {
AddMyColumn(delegate(MyObj obj) { return obj.FirstValue; });
AddMyColumn(delegate(MyObj obj) { return obj.SecondValue; });
AddMyColumn(delegate(MyObj obj) { return obj.ThirdValue; });
}
private void AddMyColumn(DelegateGrid.ValueGetter getter) {
if (lastGetter != null)
base.AddColumn(new DelegateColumn(delegate(MyObj obj) {
return getter(obj)-lastGetter(obj);
}));
base.AddColumn(new DelegateColumn(getter));
}
};
Problem
In a functional language, calculating the difference in this way would work fine, since the new delegate (constructed inside AddMyColumn) would use the value of lastGetter at the time of construction. But in C#, the new delegate uses a reference to lastGetter, so when executed, it uses the actual value at the time of execution. So the difference will always be built against the last column (i.e. obj.ThirdValue).
Solution
One solution I've found for myself is
public AddMyColumn(DelegateGrid.ValueGetter getter) {
if (lastGetter != null) {
DelegateGrid.ValueGetter newLastGetter =
new DelegateGrid.ValueGetter(lastGetter);
base.AddColumn(new DelegateColumn(delegate(MyObj obj) {
return getter(obj)-newLastGetter(obj);
}));
}
// ...
}
Note that
if (lastGetter != null) {
DelegateGrid.ValueGetter newLastGetter =
delegate(MyObject obj){return lastGetter(obj); };
wouldn't have solved the problem.
Question
Already having found a solution, this part is a bit pro forma, but
Does anyone have a suggestion for a better solution
I'm using C#2.0 and have only a theoretical knowledge of lambda expressions in C#3.0: Would they allow for a cleaner solution (and thus deserve their name...)?
The problem is just that the variable is being captured rather than the value. Here's a solution which is much the same, but slightly simpler:
public AddMyColumn(DelegateGrid.ValueGetter getter) {
if (lastGetter != null) {
DelegateGrid.ValueGetter newLastGetter = lastGetter;
base.AddColumn(new DelegateColumn(delegate(MyObj obj) {
return getter(obj)-newLastGetter(obj);
}));
}
// ...
}
Basically there's no need to create a new delegate instance - delegates are immutable, so you can just copy the value with assignment.
This isn't really a delegate-specific problem in terms of the value being captured - it's a common problem for anonymous methods and lambda expressions in general. The typical example is;
List<Action> actions = new List<Action>();
for (int i=0; i < 10; i++)
{
actions.Add(() => Console.WriteLine(i));
}
foreach (Action action in actions)
{
action();
}
This prints "10" 10 times. To print 0-9, you again need to change the scope of the captured variable:
List<Action> actions = new List<Action>();
for (int i=0; i < 10; i++)
{
int copy = i;
actions.Add(() => Console.WriteLine(copy));
}
foreach (Action action in actions)
{
action();
}
To answer your other points, lambda syntax is going to make it much nicer, since they'll reduce the verbose code.
delegate(MyObj obj) {
return getter(obj)-newLastGetter(obj);
}
Becomes:
obj => getter(obj)-newLastGetter(obj)

Categories