Determining the correct function to call based on parameter - c#

Here's my scenario:
I have ~100,000 string[] going into a function called CallCommand(string[] command).
I have ~50 static classes, that all contain the same method: public static void ParseCommand(string[] command).
My CallCommand function checks the first parameter of the string[] and calls the correct class's ParseCommand.
I'm trying to find a way to call the right function automatically (using generics?) without a switch statement.
Currently, I'm using a large switch statement like so (only showing a few since there are ~50):
public static void CallCommand(string[] command)
{
string commandVerb = command.First().ToLower();
switch (commandVerb)
{
case "add":
AddCommand.ParseCommand(command);
break;
case "attach":
AttachCommand.ParseCommand(command);
break;
case "assign":
AssignCommand.ParseCommand(command);
break;
case "cancel":
RunCommand.ParseCommand(command);
break;
case "center":
CenterCommand.ParseCommand(command);
break;
case "complain":
ComplainCommand.ParseCommand(command);
break;
default:
Log("This command doesn't exist.");
break;
}
}
I wanted to reduce the code a bit, so I tried using a Dictionary<string, Action> instead (again, reduced the number of key/value pairs here since there's ~50):
private static readonly Dictionary<string, Action<string[]>> handlers = new Dictionary<string, Action<string[]>
{
["add"] = new Action<string[]>(AddCommand.ParseCommand),
["assign"] = new Action<string[]>(AssignCommand.ParseCommand),
["attach"] = new Action<string[]>(AttachCommand.ParseCommand),
["cancel"] = new Action<string[]>(AddCommand.ParseCommand),
["center"] = new Action<string[]>(AddCommand.ParseCommand),
["complain"] = new Action<string[]>(ComplainCommand.ParseCommand)
};
Here's the CallCommand function after setting up the dictionary:
public static void CallCommand(string[] command)
{
string commandVerb = command.First().ToLower();
handlers[commandVerb].Invoke(command);
}
Finally, here's an example of one of my static classes. They are all set up exactly the same way. They just do different things in their ParseCommand method:
public static class AssignCommand
{
public static void ParseCommand(string[] command)
{
//do stuff with command
}
}
I understand I would have to refactor my static classes a bit to achieve what I want (if it's possible), I've just been unable to figure out the correct way.

Related

How can I chain methods depending on user input?

I have a method that I'm using to process images (rotate, filter, resize, etc). It looks like this:
public Image ProcessImage(Image image, Func<ImageFactory, ImageFactory> process)
{
using (var imageFactory = new ImageFactory(preserveExifData: true))
{
using (var imageStream = new MemoryStream())
{
var loadResult = imageFactory.Load(image);
var processResult = process(loadResult);
processResult.Save(imageStream);
return Image.FromStream(imageStream);
}
}
}
Since I'm using Func<> in this way I can just call the editing method I want like so:
_imageEditor.ProcessImage(_image, im => im.Resize(size))
Which means I can chain methods like:
_imageEditor.ProcessImage(_image, im => im.Resize(size).Rotate(54).Flip(true))
My question is, how can I chain these methods depending on the using input? So if my user wants to rotate and resize at the same time, I could just add the .Resize and .Rotate methods (which by the way, take different parameters).
Sure, I could use a bunch of bools but if I had a ton of editing methods it would become impossible, very very ugly to use.
Is there a way to add methods to this chain, and if so, how would you go about it?
Your question isn't 100% clear. You've left a lot of details out. But, it sounds like you are either asking how to successively invoke your methods, passing the result from one invocation to the next, or how to use inputs created at runtime to create this list of invocations, or both.
Without a Minimal, Reproducible Example, I don't have any good way to reproduce your scenario, nor to provide a solution that is specific to that scenario. But, here's a demonstration of the basic techniques you might use to accomplish those goals:
class Program
{
private static readonly Dictionary<string, Func<int[], Func<A, A>>> _parser =
new Dictionary<string, Func<int[], Func<A, A>>>()
{
{ "Init", MakeInitFunc },
{ "Add", MakeAddFunc },
{ "Multiply", MakeMultiplyFunc },
{ "Negate", MakeNegateFunc },
};
static void Main(string[] args)
{
(string, int[])[] ops =
{
("Init", new [] { 17 }),
("Add", new [] { 5 }),
("Multiply", new [] { 2 }),
("Negate", new int[0]),
};
Console.WriteLine(Chain(new A(), OpsToDelegates(ops)).Value);
Console.WriteLine(Chain(new A(), OpsToDelegates(ops).Reverse()).Value);
}
private static IEnumerable<Func<A,A>> OpsToDelegates(IEnumerable<(string Name, int[] Args)> ops)
{
foreach (var op in ops)
{
yield return _parser[op.Name](op.Args);
}
}
private static A Chain(A a, IEnumerable<Func<A, A>> ops)
{
foreach (Func<A, A> op in ops)
{
a = op(a);
}
return a;
}
private static Func<A, A> MakeInitFunc(int[] args)
{
return a => a.Init(args[0]);
}
private static Func<A, A> MakeAddFunc(int[] args)
{
return a => a.Add(args[0]);
}
private static Func<A, A> MakeMultiplyFunc(int[] args)
{
return a => a.Add(args[0]);
}
private static Func<A, A> MakeNegateFunc(int[] args)
{
return a => a.Negate();
}
}
class A
{
public int Value { get; private set; }
public A Init(int value) { Value = value; return this; }
public A Add(int value) { Value += value; return this; }
public A Multiply(int value) { Value *= value; return this; }
public A Negate() { Value *= -1; return this; }
}
There are two key elements to the above:
Given a sequence of Func<A, A> delegates, it is possible to chain them together with a simple loop. See the Chain() method for how that can be done.
Given some user input, it is possible to transform that into a sequence of Func<A, A> delegates. There is actually a very wide range of possible ways to approach that particular problem. My example shows a very simple technique, using a dictionary that maps input string values to helper methods that do the actual work of generating the elements of the sequence. See OpsToDelegates() for that.
Combining those two into this simple program, you can see how you can start with just a list of names of operations and parameters to apply them, and turn that into a functional sequence of operations actually applied to an object.
I trust you can take these general ideas and apply them to your particular scenario.
The easiest way to chain methods together is to use the Aggregate LINQ method.
You just need to change your method signature to Image ProcessImage(Image image, params Func<ImageFactory, ImageFactory>[] processes) and then you can do this:
public Image ProcessImage(Image image, params Func<ImageFactory, ImageFactory>[] processes)
{
using (var imageFactory = new ImageFactory(preserveExifData: true))
{
using (var imageStream = new MemoryStream())
{
var loadResult = imageFactory.Load(imageStream);
var processResult = processes.Aggregate(loadResult, (r, p) => p(r));
processResult.Save(imageStream);
return Image.FromStream(imageStream);
}
}
}
Now you just have to build your Func<ImageFactory, ImageFactory>[] processes from the user's selections.

Switch on one true expression c#

I would have liked to do something like
switch(true) {
case box1.Checked:
do_something(); break;
case box2.Checked:
do_something_else();
and_some_more(); break;
default:
complain_loudly();
}
But that is not allowed in c#; it is in php.
Is there a neater way, besides a
if (box1.Checked) {
do_something();
} else if (box2.checked)
...
?
With C# 7 using case with when. See also The case statement and the when clause
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApp1
{
class Program
{
static void Main(string[] args)
{
Box box1 = new Box();
Box box2 = new Box();
box2.Checked = true;
switch (true)
{
case true when box1.Checked:
Console.WriteLine("box1 is checked");
break;
case true when box2.Checked:
Console.WriteLine("box2 is checked");
break;
default:
Console.WriteLine("neither box checked");
break;
}
return;
}
}
class Box
{
public bool Checked = false;
}
}
Output:
box2 is checked
I would try something like this - find fist checked checkbox from collection and then switch-case by name of checked control...
Something like this:
var checkedCb = this.Controls.OfType<CheckBox>().Where(c => c.Checked).First();
switch (checkedCb.Name)
{
case "cbOne":
break;
case "cbTwo":
break;
default:
break;
}
PHP seems to resolve a switch differently than C#.
In C# you switch over an expression and use the cases to define possible constant results of the expression you switched over. The neat thing about the C# switch is that it might be optimized which requires the cases to be constant expressions.
Your first Problem is that your cases are not constant.
As a result of point 1: If both of your checkboxes are checked which one should be executed? This is a problem that would cause a runtime issue and cannot be evaluated at compile time. C# will not allow multiple cases of the same value.
I don't want to provide any examples of optimization here, simply because I would tell a lot of lies. If you want to know more about these optimizations you may read up to Eric Lipper's blog post about it:
https://blogs.msdn.microsoft.com/ericlippert/2009/06/11/what-does-the-optimize-switch-do/
As a solution: KISS
Keep it simple stupid - meaning - use an if else.
EDIT:
I don't think it adds to readability nor simplicity of your code. This is basically just me trying to do something weird like the switch statement you know from PHP. Please don't use it. I wouldn't recommend using it.
(It takes more space and time, initially and during each call, than a simple if else)
public partial class MainWindow : Window
{
private CheckBox[] _checkboxes;
private Dictionary<int, Action> _checkboxActions = new Dictionary<int, Action>();
public MainWindow()
{
InitializeComponent();
List<CheckBox> checkboxes = new List<CheckBox>();
checkboxes.Add(CheckBox1);
checkboxes.Add(CheckBox2);
_checkboxes = checkboxes.ToArray();
_checkboxActions.Add(CheckBox1.GetHashCode(), OnCheckBox1Checked);
_checkboxActions.Add(CheckBox2.GetHashCode(), OnCheckBox2Checked);
}
public void InvokeCheckboxActions()
{
Action action;
foreach(var checkbox in _checkboxes)
{
if(checkbox.IsChecked == true)
{
int checkboxPtr = checkbox.GetHashCode();
if(_checkboxActions.TryGetValue(checkboxPtr, out action))
{
action();
}
}
}
}
private void OnCheckBox1Checked()
{
Console.WriteLine("Checkbox 1 was checked");
}
private void OnCheckBox2Checked()
{
Console.WriteLine("Checkbox 2 was checked");
}
}
I think this code will have desired behavior.
public enum Mode { None, Break, Continue };
public sealed class Branch<T>
{
public Mode Mode { get; }
public T Value { get; }
public Action Action { get; }
public Branch(T value, Action action, Mode mode = Mode.None)
{
Value = value;
Action = action;
Mode = mode;
}
}
public static class CaseHelper
{
public static void Switch<T>(T condition, params Branch<T>[] branches)
{
bool Continue = false;
foreach (var branch in branches)
{
if (branch.Value.Equals(condition) || Continue)
{
branch.Action();
}
if (branch.Mode == Mode.Break) break;
Continue = branch.Mode == Mode.Continue;
}
}
}
usage:
CaseHelper.Switch(true, new Branch<bool>(box1.Checked, doSomething1), new Branch<bool>(box2.Checked, () => doSomething2()));
but it looks not very elegant
P.S.:
We can add implicit conversion operator to Branch
public static implicit operator Branch<T>(Tuple<T, Action, Mode> triple)
{
return new Branch<T>(triple.Item1, triple.Item2, triple.Item3);
}
public static implicit operator Branch<T>(Tuple<T, Action> duple)
{
return new Branch<T>(duple.Item1, duple.Item2);
}
and use something like this:
CaseHelper.Switch(true,
(Branch<bool>)Tuple.Create<bool, Action>(box1.Checked, doSomething1),
(Branch<bool>)Tuple.Create<bool, Action, Mode>(box2.Checked, () => doSomething2(), Mode.Break)
);

Creating A Command Based Application Without Extensive Use Of If-Else Statements

I have this C# application i want to work on. It is mostly command based and what I mean with this is that the user enters some type of command and the application simply performs some kind of task.
For example: User can type in a command such as getdate, the application reads this command and simply displays a date.
NOTE: Its going to be console based but my problem, the actual application has about 80 to 100 commands and my question is how to read this command without relying on some verbose if-else statement to check which command was typed in.
Is there a way I can do this or I just have to go with some long if-else statements.
There are several options you could take:
You could have a hastable of the commands that map to the type to initialize.
Dictionary<string, Type> Where type maps to the class you initialize.
Use Reflection to directly map the command to an object to initialize (via object name or an attribute.
[Command(Name = "update")]
public class RunUpdates : ICommand {
}
[Command(Name = "restart")]
public class RestartServer : ICommand {
}
Then use reflection to find the object that implements ICommand with the attribute matching the command name.
Use a simple form of Command Pattern along with some kind of Command Collection.
A simple way to build this would be:
public class MyApp
{
private readonly Dictionary<string, Action> _commands = new Dictionary<string, Action>();
public static void Main()
{
var program = new MyApp();
// Run Console Stuff
}
public MyApp()
{
SetupCommands();
}
public void SetupCommands()
{
_commands.Add("PrintDate", () => Console.WriteLine(DateTime.Now));
_commands.Add("PrintMaxOf3And7", () => Console.WriteLine(Math.Max(3, 7)));
}
public void ExecuteCommand(string commandName)
{
_commands[commandName].Invoke();
}
}
Use delegate:
public delegate void CommandDelegate(string input);
public Dictionary<string, CommandDelegate> Commands { get; set; }
/// usage
public void InitCommands()
{
Commands.Add("showdata", (input) => Console.WriteLine(....));
... // other commands
}
public void ExecuteCommand(string userInput)
{
var firstWord = userInput.Substring(0, userInput.IndexOf(" "));
if (Commands.ContainsKey(firstWord))
{
var command = Commands[firstWord];
command(userInput);
}
}
You could use a dictionary that uses string as keys and methods (either Action, Func or a custom delegate) as value, then you just need to reas the input from the user and use it a key key to get the corresponding action. If the command can have parameters like this command param1 then use string.Split to separate the command from the parameter, then use the command string as key, and when you execute the method pass the other string as parameter (depending of the type of data of the parameter to may need to parse the parameter of the command from string to something else)
The code would look like this:
Using Func:
NOTE: Func requires at least one parameter and a return value.
void Main()
{
public Dictionary<string, Func<string, int>> commands =
new Dictionary<string, Func<string, int>>();
commands.Add("getdate", GetDate);
Console.WriteLine("Enter a command");
string input = Console.ReadLine(); //<-- Try typing "getdate"
commands[input].Invoke();
}
public int GetDate(string someParameter)
{
Console.WriteLine(DateTime.Today);
return 0;
}
Using Action:
NOTE: Action requires at least one parameter.
void Main()
{
public Dictionary<string, Action<string>> commands = new Dictionary<string, Action>();
commands.Add("getdate", GetDate);
Console.WriteLine("Enter a command");
string input = Console.ReadLine(); //<-- Try typing "getdate"
commands[input].Invoke();
}
public void GetDate(string someParameter)
{
Console.WriteLine(DateTime.Today);
}
Using Custom Delegate:
public delegate double YourDelegate(string param);
void Main()
{
public Dictionary<string, YourDelegate> commands =
new Dictionary<string, YourDelegate>();
commands.Add("getdate", GetDate);
Console.WriteLine("Enter a command");
string input = Console.ReadLine(); //<-- Try typing "getdate"
commands[input].Invoke();
}
public double GetDate(string someParameter)
{
Console.WriteLine(DateTime.Today);
return 0.0;
}
You could use switch, or you could create a Dictionary with question as key and command as value. Suggest you do a ToLower() on both key and input to make it case insensitive, as relying on user to type perfectly will be difficult.
private Dictionary<string,object> commandList = new Dictionary<string,object>();
private void processCommand(){
commandList.Add("showdate",DateTime.Now);
string command = Console.ReadLine();
if(command.Length>0){
if(commandList.ContainsKey(command);
object o = commandList[command.ToLower()];
//do something
}
}
}

Switch Statement in C# Class

I have a csharp app with a xml config file containing an element called "environment" which can be set to different values (development/test/production for example).
When this config file entry is modified the resulting global variables within the application should all change. I have a class in my application called Globals were I am storing global variables. I want to add a case/switch element to it but it won't seem to work.
So for example I have the following defined at the top of the globals class:
public static string environment = MyApp.Properties.Settings.Default.Environment;
Then lower down in my class I'm trying to do the following:
switch (environment)
{
case "development":
public static string Server = "SQL1";
public static string Username = "dev.user";
case "test":
public static string Server = "SQL2";
public static string Username = "test.user";
case "production":
public static string Server = "SQL3";
public static string Username = "prod.user";
default:
public static string Server = "SQL1";
public static string Username = "dev.user";
}
(In the example above I reduced the number of variables to two just to make it more understandable but in reality there are probably 30 variables per environment.)
This doesn't work I get multiple errors:
Invalid token 'switch' in class, struct, or interface member declaration
Invalid token ')' in class, struct, or interface member declaration
Invalid token 'case' in class, struct, or interface member declaration
Is there some other way of doing this?
Thanks
Brad
public static class Globals
{
public static string Environment = MyApp.Properties.Settings.Default.Environment;
public static string Server;
// rest of code
public static void LoadEnvironment()
{
switch (Environment)
{
case "development":
{
Server = "SQL1";
Username = "dev.user";
break;
}
// rest of code
}
}
}
Based on the error the compiler thinks it is coded inside the body of the class. Try moving the logic inside a method or some such and this may be due to your access modifiers inside your switch statement - eg. public static etc
public static should be declare in the class scope, not within a function.
You can initializes static variable either in the line of declaration or within the static constructor.
You forgot puting "break at the end of each case.
So the code should looke like this:
public class MyClass
{
public static string Server;
public static string Username;
static MyClass()
{
switch (environment)
{
case "development":
Server = "SQL1";
Username = "dev.user";
break;
case "test":
Server = "SQL2";
Username = "test.user";
break;
case "production":
Server = "SQL3";
Username = "prod.user";
break;
default:
Server = "SQL1";
Username = "dev.user";
break;
}
}
}
Try to define your strings before the switch statement. For each case, you have to define a break statement to make the pointer get out of the switch structure.
For your case, it's a good idea to define the Server and Username as properties and in a static constructor of a static class, define these values from the object. For sample:
public static class Globals
{
// define properties
public static string Server { get; set; }
public static string Username { get; set; }
// encapsulate the Settings.Environment in a property
public public static string Environment
{
get { return MyApp.Properties.Settings.Default.Environment; }
}
// when the application starts, this static scope will execute!
static Globals()
{
switch (environment)
{
case "development":
Server = "SQL1";
Username = "dev.user";
break;
case "test":
Server = "SQL2";
Username = "test.user";
break;
case "production":
Server = "SQL3";
Username = "prod.user";
break;
default:
Server = "SQL1";
Username = "dev.user";
}
}
}
To use it, just call
var server = Globals.Server;
var user = Globals.Username;

Call a method dynamically based on some other variable [duplicate]

This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
How to Call method using its name?
Getting sick of using switch/case statements. I'm wondering if there is some way to call a method based on the value provided by the user. Understand that there could be a million reasons why this is a bad idea, but here's what I'm thinking:
Console.Write("What method do you want to call? ");
string method_name = Console.ReadLine();
then somehow call the method contained in 'method_name'. Is this even possible?
You can use reflection:
var type = typeof(MyClass);
var method = type.GetMethod(method_name);
method.Invoke(obj, params);
If you want the type to be dynamic as well as the method then use this instead of typeof(MyClass):
var type = Type.GetType(type_name);
Many times you can refactor switch statements to dictionaries...
switch (caseSwitch)
{
case 1:
Console.WriteLine("Case 1");
break;
case 2:
Console.WriteLine("Case 2");
break;
case 3:
Console.WriteLine("Case 3");
break;
}
can become ...
var replaceSwitch = new Dictionary<int, Action>
{
{ 1, () => Console.WriteLine("Case 1") }
{ 2, () => Console.WriteLine("Case 2") }
{ 3, () => Console.WriteLine("Case 3") }
}
...
replaceSwitch[value]();
This is a very subtle shift that doesn't seem to gain much, but in reality it's much, much better. If you want to know why, this blog post explains it very well.
Instead of reflection, if you have to act on the user's input value w/o using switch statement, you could use a dictionary having the list of methods mapped against the input value.
private static void Method1(int x)
{
Console.WriteLine(x);
}
private static void Method2(int x)
{
}
private static void Method3(int x)
{
}
static void Main(string[] args)
{
Dictionary<int, Action<int>> methods = new Dictionary<int, Action<int>>();
methods.Add(1, Method1);
methods.Add(2, Method2);
methods.Add(3, Method3);
(methods[1])(1);
}
Your sample
public class Boss
{
public void Kick()
{
Console.WriteLine("Kick");
}
public void Talk(string message)
{
Console.WriteLine("Talk " + message);
}
public void Run()
{
Console.WriteLine("Run");
}
}
class Program
{
static void AutoSwitch(object obj, string methodName, params object[] parameters)
{
var objType = typeof(obj);
var method = objType.GetMethod(methodName);
method.Invoke(obj, parameters);
}
static void Main(string[] args)
{
var obj = new Boss();
AutoSwitch(obj, "Talk", "Hello World");
AutoSwitch(obj, "Kick");
}
}
Another interesting way I have seen to handle(read avoid) switch statements differently is to use a dictionary of methods. I stole this from http://www.markhneedham.com/blog/2010/05/30/c-using-a-dictionary-instead-of-if-statements/ and it looks like they are using the MVC framework but the same basic principal applies
public class SomeController
{
private Dictionary<string, Func<UserData,ActionResult>> handleAction =
new Dictionary<string, Func<UserData,ActionResult>>
{ { "Back", SaveAction },
{ "Next", NextAction },
{ "Save", SaveAction } };
public ActionResult TheAction(string whichButton, UserData userData)
{
if(handleAction.ContainsKey(whichButton))
{
return handleAction[whichButton](userData);
}
throw Exception("");
}
private ActionResult NextAction(UserData userData)
{
// do cool stuff
}
}
If you're thinking you could somehow do this:
Console.Write("What method do you want to call? ");
string method_name = Console.ReadLine();
method_name();
You are mistaken. You have to analyze the user input and call a method based on that.
Sure, reflection is your friend. Have a look at Type.GetMethod().

Categories

Resources