Switch statement with Multiple conditions - c#

I am writing a C# web-testing project for an application that will read a value from an XML config file and perform automated testing. The code I have right now is working, however, it has to be changed every time the requirements are updated.
private void takeAction(string keyData, string locator, string action)
{
switch (keyData)
{
case "Origin":
if (action == "Input")
{
origin_input(locator, "MEL");
}
break;
case "Destination":
if (action == "Input")
{
destination_input(locator, "Manila");
}
break;
case "DepartDate":
if (action == "Input")
{
textinput(locator, "21/10/2014");
}
break;
case "ReturnDate":
if (action == "Input")
{
textinput(locator, "06/11/2014");
}
break;
case "Adult":
if (action == "Select")
{
objSelect(locator, "3");
}
break;
case "SearchButton":
if (action == "Button")
{
objClick(locator);
}
break;
...
}
}
This code matches the name of the object, checks the required action, and then calls the appropriate function with a few parameters.
I have read some examples of the Open/Closed Principle, however, I could not solve this issue as there are multiple conditions being checked at same time.
As more "keydata" will be added into the code, I believe the switch statement does not seem to be the correct option here. Any advice on improving this code would be appreciated.

IF I were you I'd use some sort of abstraction. For instance all methods you call inside the individual if statements within the switch take string locator and an optional other string parameter (or none in the last case). Furthermore I think you can simplify the logic by combining the value of the keyData and the acton parameters since when combined they produce unique key.
What you can do with this is the following:
public interface ITestableAction{
void Execute(string locator);
}
public class OriginInputAction : ITestableAction{
public void Execute(string locator){
origin_input(locator, "MEL"); //I'd make the origin_input method static...
}
}
public class DestinationInputAction : ITestableAction{
public void Execute(string locator){
destination_input(locator, "Manila");
}
}
finally your class needs to have a dictionary where the keyData and the acton will represent the keys.
private Dictionary<string, ITestableAction> actions =
new Dictionary<string, ITestableAction>();
actions.Add("OriginInput", new OriginInputAction());
actions.Add("DestinationInput", new DestinationInputAction());
etc...
so in your method instead of constantly having to check the different ways you can pair all keyData and action values you simply look up the corresponding ITestableAction for their sum:
private void takeAction(string keyData, string locator, string action)
{
string key = string.Format("{0}{1}", keyData, action);
if(actions.ContainsKey(key))
{
ITestableAction action = actions[key]
action.Execute(locator);
}
}
This is one of the "I am supposed to know it" design patterns. Can't really put my finger on what exactly it is, but it's useful. It's supposed to help you because you don't have change the logic so much every time. Just create a new class that inherits from ITestableAction and add it to the dictionary. At the end of the day the logic tree becomes shorter. But then again, please don't take this at face value... there are hundreds of ways to code something, and only you know your requirements and stakes. This is just a suggestion to hopefully point you in the right direction.
Thanks,
Martin.

You could declaratively define your cases as shown below. You could also use classes, but that gets more complicated because the classes need access to the methods that you're passing locator into. If this approach still calls for more separation, then it might be worth making each case into a class.
Interface
public delegate void TestAction(string locator);
public class ActionCase
{
public string ExpectedAction { get; set; }
public TestAction Test { get; set; }
}
Definitions
private Dictionary<string, ActionCase> cases = new Dictionary<string, ActionCase>
{
{
"Origin",
new ActionCase
{
ExpectedAction = "Input",
Test = locator => origin_input(locator, "MEL")
}
},
//Define the rest here
};
Usage
private void takeAction(string keyData, string locator, string action)
{
var case = cases[keyData];
if (action == case.ExpectedAction)
case.Test(locator);
}

Well, you could simply do something like:
switch (keyData + action)
{
case "OriginInput":
origin_input(locator, "MEL");
break;
}

I think you just need an extra variable
private void takeAction(string keyData, string locator, string action, string searchfor)
{
switch (keyData)
{
case "Origin":
if (action == "Input")
{
origin_input(locator, searchfor);
}
break;

Related

Single instance of a helper object with parameters

One of our projects makes use of key-value pairs where certain runtime parameters - that do not change per instance of the program - determine the value gotten. For example:
Program run in test mode with the parameter "Municipal":
Key: "testMunicipalDirectory"
Value: "C:\Foo\Bar\"
Program run with the parameter "State":
Key: "StateDirectory"
Value: "C:\Bar\Baz\"
To make it slightly more complicated, if there is no matching key for, say "testMunicipalImagesDirectory", there is a fallback of "defaultImagesDirectory":
Key: "testMunicipalImagesDirectory" ?? "defaultImagesDirectory"
Value: "C:\Foo\Bar\Images" ?? "C:\Images"
Currently, there's a lot of code duplication/inefficiencies, and room for error. Every time one of these is referenced there's string concatenation and null-coalescing and other stuff going on.
It seems like this would benefit from a single-instance object that is passed certain parameters on initialization (test or not, "State" or "Municipal", etc), that will return the correct values for each different property the keys represent.
Many answers I found to questions asking how to use the singleton design pattern with parameters basically boil down to "if it uses parameters, you probably do not want a singleton". In my case, it is invalid to attempt to initialize the object with different values, and an exception should be thrown if this happens.
This is how I would accomplish this goal (pseudo-C#) (lazy-loading is not a requirement but is used here):
public sealed class Helper
{
// how can we enforce that Init has been called?
private static readonly Lazy<Helper> lazyLoader = new Lazy<Helper>(() => new Helper(name, test));
public static Helper Instance { get { return lazyLoader.Value; } }
public static void Init(string name, bool test)
{
// if it has already been initalized
throw new InvalidOperationException("This has already been initalized.");
// else initalize it
}
private string Name { get; set; }
private bool Test { get; set; }
private Helper(string name, bool test) { } // assign to properties, any other ctor logic
public string Directory
{ get { return ValueGetter.Get((this.Test ? "test" : "") + this.Name + "Directory"); } }
}
public static class ValueGetter
{
public static string Get(string key, string fallbackKey)
{
if (Keys.Any(k => k == key))
return Keys[key].Value;
else
return Keys[fallbackKey].Value;
}
}
But as you can see, there are questions remaining. How can it enforce calling Init before using the Instance, but not require those parameters to be passed every time Instance is accessed?
Is this the correct direction to go, or is there a better design pattern to use?

How Call Method<T> Generic

I have a problem on having called a generic method, I have searched very much and do not find a solution, this one is my mistake.
And I do not have knowledge of I am doing badly,
The type arguments for method 'FormGasolineUserControl.loadList<T>(list<T>,string)' cannot be inferred from the usage. try specifying the type arguments expliciy.
this is my code:
This chunk of code where I obtain the error
private void loadDataForm()
{
try
{
DateTime dateNow = DateTime.Now;
// Call Services WPF
var QueryBD = services.LoadDataFormGasoline(1, (int)ETax.Gasoline);
if (QueryBD.Company != null)
{
day.Value = dateNow.Day.ToString();
month.Value = dateNow.Month.ToString();
year.Value = dateNow.Year.ToString();
anioGravable.Value = dateNow.Year.ToString();
peridoGravable.Value = PeriodoGravable(dateNow).ToString();
//Error call Method
loadList( QueryBD.QualityDeclarate, QualityDeclarate.Name.ToString());
loadList( QueryBD.TypeDeclarate, TypeDeclarate.Name.ToString());
}
}
catch (Exception)
{
throw;
}
}
And this one is the method:
public void loadlist<T>(List<T> lista,string nameControl)
{
try
{
switch (nameControl)
{
case "TypeDeclarate":
TypeDeclarate.Items.Add(new ListItem("Select..."));
foreach (var name in lista)
{
TypeDeclarate.Items.Add(new ListItem(name.ToString()));
}
break;
case "QualityDeclarate":
QualityDeclarate.Items.Add(new ListItem("Select..."));
foreach (var name in lista)
{
QualityDeclarate.Items.Add(new ListItem(name.ToString()));
}
break;
}
}
catch (Exception)
{
throw;
}
}
My principal aim is to be able to load the usercontrol dynamicamente by means of lists consulted in database.
help me plis...
This code could be improved in a great many ways.
It should not be generic.
It could be refactored into smaller methods that are more clear.
The naming conventions do not follow C# conventions.
It takes a list but only enumerates the elements
It really operates on sequences of strings.
The try-catch is useless.
Let's fix it.
private void AddItemsToCollection(IEnumerable<string> names, IList<ListItem> items)
{
items.Add(new ListItem("Select..."));
foreach (var name in names)
items.Add(new ListItem(name));
}
See how simple that is? Make simple methods that do one thing well. Now we use that helper to make other simple methods:
private void AddItemsToCollection(IEnumerable names, IList<ListItem> items)
{
AddItemsToCollection(names.Cast<object>().Select(n => n.ToString(), items);
}
Again, super simple. One line. Let's make more one-liners:
public void AddTypeDeclarateItems(IEnumerable names)
{
AddItemsToCollection(names, TypeDeclarate.Items);
}
SO EASY. Do it again.
public void AddQualityDeclarateItems(IEnumerable names)
{
AddItemsToCollection(names, QualityDeclarate.Items);
}
And now our method is simple:
public void AddItemsToCollection(IEnumerable names, string control)
{
switch (control)
{
case "TypeDeclarate":
AddTypeDeclarateItems(names);
break;
case "QualityDeclarate":
AddQualityDeclarateItems(names);
break;
}
}
Your code will get easier to understand, easier to make correct, easier to debug, if you simplify it so that every method does one thing.
Alternative solution: move the switch into a helper:
IList<ListItem> GetItems(string control)
{
switch (control)
{
case "TypeDeclarate":
return TypeDeclarate.Items;
case "QualityDeclarate":
return QualityDeclarate.Items;
}
throw new SomeException(...);
}
And now our method is:
public void AddItemsToCollection(IEnumerable names, string control)
{
AddItemsToCollection(names, GetItems(control));
}
Again, see what happens when you make every method do one thing? Every method gets really easy to understand, and highly likely to be correct.
This is the correct way to call this method:
...
loadlist<string>(QueryBD.myListOfStrings, "nameControl");
loadlist<int>(QueryBD.myListOfInts,"nameControl");
...
But, I guess that maybe the problem is inside the class that contains the method
void loadlist<T>(List<T> lista,string nameControl).
Aswer this question: What is T? I mean, in a class declaration we have many possibilities.
We can set T argument like a class: public MyClass<T> where T : class;
A struct: public MyClass<T> where T : struct; A class that has a public constructor public MyClass<T> where T : new(),...
See all possibilities: https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/generics/constraints-on-type-parameters
So, let's imagine that T is a class that must implements an interface and you're passing a class that doesn't implement it, so you'll not have success.

How to store a list of Cases from Switch Statement?

In my program I have a listbox that when the user double clicks an object it looks to a switch statement to see what event should occur. As the list begins getting larger I'm curious if there is a way to avoid having to maintain the list of objects in 2 places (once in a list to Add to the listbox, and once in the switch statement.
Is there a way to index/read/store the various Cases of my switch statement, then add them as objects to my listbox?
Example: (doesn't work, just a theory)
Switch (n)
ForEach (Case c in Cases)
{
arrayCases.Add(c);
}
listbox.Items.AddRange(arrayCases);
EDIT:
Going on the Dictionary recommendations I now have:
public void SetDictionary()
{
//add entries to the dictionary
dict["cat"] = new Action(Cat);
dict["dog"] = new Action(Dog);
//add each dictionary entry to the listbox.
foreach (string key in dict.Keys)
{
listboxTest.Items.Add(key);
}
}
//when an item in the listbox is double clicked
private void listboxTest_DoubleClick(object sender, EventArgs e)
{
testrun(listboxCases.SelectedItem.ToString());
}
public void testrun(string n)
{
//this is supposed to receive the item that was double clicked in the listbox, and run it's corresponding action as defined in the dictionary.
var action = dict[n] as Action action();
}
I believe that my code above is mostly correct and that I'm understanding it, however the action line:
var action = dict[n] as Action action();
Shows an error stating 'action' is expecting a ';'. Is my logic here accurate? If so, why is the action call incorrect?
Dictionary<string, Action> is the way to avoid. Dictionary.Keys becomes ListBox.Items.
switch(n) becomes
var action = dict[n] as Action
action();
I suggest to move your operations into separate classes. Create a base class for your operations like the following one. I added a field for the form because you probably have to interact with your form. You can also pass in other objects if required.
internal abstract class Operation
{
protected readonly MyForm form = null;
protected Operation(MyForm form)
{
this.form = form;
}
public abstract String DisplayName { get; }
internal abstract void Execute();
}
Then derive one class for each operation.
internal sealed class DoThis : Operation
{
internal DoThis(MyForm form) : base(form) { }
public override String DisplayName
{
get { return "Do this!"; }
}
internal override void Execute()
{
// Code to do this. You can use this.form to interact with
// your form from this operation.
}
}
internal sealed class DoSomethingElse : Operation
{
internal DoSomethingElse(MyForm form) : base(form) { }
public override String DisplayName
{
get { return "Do something else!"; }
}
internal override void Execute()
{
// Code to do something else.
}
}
Now you can add all your operations to the list box
this.lsitBox.Items.Add(new DoThis(this));
this.lsitBox.Items.Add(new DoSomethingElse(this));
and set the display member property.
this.listBox.DisplayMember = "DisplayName";
Finally execute the selected operation in the event handler.
((Operation)this.listBox.SelectedItem).Execute();
This pattern gives clean separation between all your operations and makes future extensions easy and clean. For example you could add a property CanExecute to all operations if you have to check if a operation is currently available. Or if you have to support localization it is easy to add logic for presenting the name of the operation in the current UI language.
Another scenario that is easily supported is if you have some code common to all operations for example logging, security checks, performance measuring and things like that.
internal abstract class Operation
{
protected readonly MyForm form = null;
protected Operation(MyForm form)
{
this.form = form;
}
public abstract String DisplayName { get; }
protected abstract void ExecuteCore();
internal void Execute()
{
Logger.Log("Executing operation " + this.DisplayName);
try
{
this.ExecuteCore();
Logger.Log("Executing operation " + this.DisplayName + " succeeded.");
}
catch (Exception exception)
{
Logger.Log("Executing operation " + this.DisplayName + " failed.", exception);
throw;
}
}
}
Note that you now have to override ExecuteCore() instead of Execute().
One final thought - using an interface IOperation instead or in combination with the abstract base class may be helpful, too. This removes the need that all operation inherit from the same base class because this might sometimes be inconvenient. But I omitted this to not overengineere this even more.
You can't* enumerate case of switch with normal code.
What you can do instead is to replace switch with map of "action name" to "action handler" and than you'll be able to reuse this map for list of action names listbox. See Tilak's answer for sample.
*) If you are really inquisitive you can enumerate choices of switch. C# code is transformed to IL and IL can be read with code. So you can get IL for a method, write (or get existing - Parser for C#) parser for IL and find implementation of switch inside the method, pick all cases. You can even go straight to C# source at build time - but it is even more involved than IL parsing.
Yes there is a way to do this by making a dictionary of lambdas.
void Main()
{
// set up your dictionary
Dictionary<string,Action> myList = new Dictionary<string,Action> {
{ "one", () => { Console.WriteLine("One function"); } },
{ "two", () => { Console.WriteLine("Two function"); }},
{ "three", () => { Console.WriteLine("Three function"); }}
};
// do a "switch" (that is invoke a function that corresponds to a name)
myList["one"]();
// loop the list of keys (that is get a list of all the names)
foreach (string key in myList.Keys)
Console.WriteLine(key);
}
the output of this program:
One function
one
two
three
Also note -- you can add to this "switch" dynamically like this (which is cool and something you can't do with a classical switch statement.)
myList.Add("four",() => { Console.WriteLine("Four function is dynamic"); });
It sounds to me like the number of cases in your switch are going to change a lot. If this is true, then you might want to consider using a mechanism other than a switch statement. Perhaps you want to do something like Alexi Levenkov suggests, and then iterate a list of the stored Action Names and execute the associated handler. This way you will avoid having to add the action name to the action map and then add it to the switch.

How to execute two code fragments in different sequence?

I have a code with next logic: If some boolean flag is true, one of two code fragments must be executed first and vice versa. But both of them must be executed always. Unfortunately, C# has not semantics instructions for that, like this:
if (condition) first
{
//Some code to execute first if condition is true
}
second
{
//Some code to execute first if condition is false
}
Now, I to do so:
if (condition)
{
//Code 1
//Code 2
}
else
{
//Code 2
//Code 1
}
Such neccesserities are numerous and this creates many code duplication. May be is there a better solution?
Put the code into seperate methods
public void MyMethod1
{
//first code goes here
}
public void MyMethod2
{
//second code goes here
}
if (condition)
{
MyMethod1();
MyMethod2();
}
else
{
MyMethod2();
MyMethod1();
}
This way you do not have to duplicate the code inside the methods.
You may consider writing a method such as:
public static void DoBoth(Action first, Action second, bool keepOrder)
{
if (keepOrder)
{
first();
second();
}
else
{
second();
first();
}
}
I'd create two methods with "Code 1" and "Code 2", then go on like your 2nd option:
if (condition)
{
Code1(); Code2();
}
else
{
Code 2(); Code1();
}
You could also polish this up via Actions or Delegates, depending on what "code 1" and "code 2" are.
I agree with #Steven Jeuris comment about preferring to know the underlying reason as it may point to a design decision requiring improvement. However, if you need to stick with what you have, I would suggest a queue of delegates since you imply that your example is very simple compared to the actual codebase. If not, then one of the other answers would be fine, but the below is possibly more maintainable as complexity grows.
Note: I'm putting this as an example - the parameters for GetQueue, and the logic inside it, could be improved depending on what your conditions actually are.
public Queue<Action> GetQueue(bool condition)
{
var toReturn = new Queue<Action>();
if (condition)
{
toReturn.Enqueue(DoWork1);
toReturn.Enqueue(DoWork2);
}
else
{
toReturn.Enqueue(DoWork2);
toReturn.Enqueue(DoWork1);
}
return toReturn;
}
public void MyExecutingMethod()
{
foreach (var action in GetQueue(true))
{
action();
}
}
public void DoWork1()
{
}
public void DoWork2()
{
}
You should try to avoid code duplication whenever you can. The basic idea in your case would be to try and extract everything that seems to be done more than once and try to "put" it somewhere where you only need to write it once.
In your case, say we have the following:
public void Bar()
{
...
if (condition)
{
//code for action 1
//code for action 2
}
else
{
//code for action 2
//code for action 1
}
...
}
public void Foo()
{
...
if (condition)
{
//code for action 1
//code for action 2
}
else
{
//code for action 2
//code for action 1
}
...
}
Now we obviously can see that you have some code duplication here. We can improve this the following way:
public void Bar()
{
...
if (condition)
{
Action1();
Action2();
}
else
{
Action2();
Action1();
}
...
}
public void Foo()
{
...
if (condition)
{
Action1();
Action2();
}
else
{
Action2();
Action1();
}
...
}
private void Action1()
{
//code for action 1
}
private void Action2()
{
//code for action 1
}
This looks a lot better (specially if Action1 code and Action2 code is lengthy). We have now managed to write the code for Action1 and Action2 only once no matter how many Foo or Bar style methods we have in our code. But we can still do more. You can see that we are still duplicating some obnoxious verbose code. So we can take it a step further and do the following:
public void Bar()
{
...
DoAction(condition);
...
}
public void Foo()
{
...
DoAction(condition);
...
}
private void Action1()
{
//code for action 1
}
private void Action2()
{
//code for action 1
}
private void DoAction(bool condition)
{
if (condition)
{
Action1();
Action2();
}
else
{
Action2();
Action1();
}
}
Now, that IMHO looks a lot better. Not only have we managed to write Action1 and Action2 specific code only once, we have now also managed to write that pesky method ordering logic only once too.
This has huge implications on readability and above all maintainability. For instance, if a bug crops up in Action1 now you only need to change it in one single place. In the original implementation you would have to check all the code and fix the bug everywhere.
Also, imagine the method ordering is business rules dependant, and your client (oh my what a surprise!) decides to change them. With the latest implementation you only need to change your code in one spot.
Rule of the thumb: Avoid code duplication whenever you can, it will drastically reduce the code you type and the headaches you or some poor soul will have in the near future.
I'm going to hazard a guess that code1 either have no side effects or act on the classes member variables, in which case they can be wrapped up in methods that return void. You could then do something along the lines of the following:
...
if (condition)
DoWork(() => Code1(), () => Code2());
else
{
DoWork(() => Code2(), () => Code1());
}
...
private void Code1()
{
// Code 1
}
private void Code2()
{
// code 2
}
private void DoWork(Action action1, Action action2)
{
action1();
action2();
}
I offer another suggestion (in pseudocode).
EDIT: It really depends on your situation which of various approaches you will want to take. Benefits of this approach are simplicity and flexibility. By flexibility, I mean that the decision on ordering is now separated from the code so you can easily do things like add a new ordering, or let the ordering be specified in some other means (e.g. what if you now want to associate different orderings with different users based on a property file)?
if(condition)
runOrder = [ "one", "two" ];
else
runOrder = [ "two", "one" ];
for(x=0; x<runOrder.length; x++)
{
codeToRun = runOrder[x];
switch(codeToRun)
{
Case "one": Code1();
Case "two": Code2();
}
}

need to create a summary of a large switch statement in C#

Alright, i dont know how to explain it well.. but i have a switch statement,
string mystring = "hello";
switch(mystring)
{
case "hello":
break;
case "goodbye":
break;
case "example":
break;
}
of course this is an example, and in the real situation, there will be different things happening for each case.
ok, hope you get the point, now, doing this manually is impossible, because of the sheer number of different case's. i need to respectively create a list, of all the cases, so for instance.. for the above switch statement, i would need
string[] list = { "hello", "goodbye", "example" };
maybe could be done with a foreach some how i dont know, any help would be greatly appreciated.
also, any working codes provided would be awesome!
edit:
people are asking for more detail, so here is how it works.
the user of the program, inputs a series of strings.
based on the string(s) they entered, it will do a few if's and else if's and throw back the new strings basically. i need to be able to be able to create a list, through the program, of all the options available to use. and i cant just make a list and hard code it in, because im always adding more case's to the statement, and i cant be going back and keeping a list up to date.
FOR VISUAL STUDIO:
if mystring is an enum instead of a string, in visual studio, if you type "switch" [TAB] "mystring" [ENTER] it'll build the long switch for you with all the cases.
It depends on how clever you want to get... You could create a custom attribute that attaches to a method with the string that method should handle. Then, instead of a switch statement, you would just find the attribute with your desired value and execute it.
using System;
using System.Reflection;
namespace ConsoleApplication1 {
[AttributeUsage(AttributeTargets.Method)]
internal class ProvidesAttribute : Attribute {
private String[] _strings;
public ProvidesAttribute(params String[] strings) {
_strings = strings;
}
public bool Contains(String str) {
foreach (String test in _strings) {
if (test.Equals(str)) {
return true;
}
}
return false;
}
}
internal class Program {
[Provides("hello", "goodbye")]
public void HandleSomeStuff(String str) {
Console.WriteLine("some stuff: {0}", str);
}
[Provides("this")]
public void HandleMoreStuff(String str) {
Console.WriteLine("more stuff: {0}", str);
}
public void HandleString(String str) {
// we could loop through each Type in the assembly here instead of just looking at the
// methods of Program; this would allow us to push our "providers" out to other classes
MethodInfo[] methods = typeof(Program).GetMethods();
foreach (MethodInfo method in methods) {
Attribute attr = Attribute.GetCustomAttribute(method, typeof(ProvidesAttribute));
ProvidesAttribute prov = attr as ProvidesAttribute;
if ((prov != null) && (prov.Contains(str))) {
method.Invoke(this, new Object[] { str } );
break; // removing this enables multiple "providers"
}
}
}
internal static void Main(String[] args) {
Program prog = new Program();
foreach (String str in args) {
prog.HandleString(str);
}
}
}
}
Once you have the framework, you wouldn't need to alter the HandleString() code, just add the methods you want to take care of and set the Provides attribute on them. If you wanted to extend the idea a little further, you could create multiple classes to handle a wide variety of strings, then loop through each type in your assembly looking for the Provides attribute.
EDIT this has the added benefit that you can define multiple methods that act on the same string (by removing the break in the loop logic).
I'm note sure what you are trying to do, but you might be able to use a dictionary.
Dictionary<string, int> lookupTable = new Dictionary<string, int>();
lookupTable.Add("hello", 1);
lookupTable.Add("goodbye", 2);
lookupTable.Add("example", 3);
int output = lookupTable["hello"];
You wouldn't need to have code to add each individual entry. You could read in the keys and values from a file, loop though them and populate the dictionary.
If you explain more about what you are trying to do, we could give you more specific advice.
By proper refactoring (your hypothetical example) you can make sure that out of your sheer number of cases, there will be a lot of them that can call the same sub routine with their string parameter.
In many of these scenarios, you may not even need a huge switch statement, but just parameterize one sub routine that can handle them.
Without a concrete example of what you want to do in the case statements, it is hard to come up with a concrete answer.
You appear to be trying to extract "command strings" from your code, so that you can automatically update the list of available commands in your user documentation. I think this will not gain you much, as you will still need to manually document what each command does.
That being said, the following powershell command will extract the data you want from test.cs:
type test.cs|select-string 'case "(.*)"'|foreach {$_.Matches[0].Groups[1].Value}
Switch statements evaluate on constants, so the case statements won't work with variables. Perhaps you should consider using a Dictionary<> and branching based on that. But without any more insight into the problem you're solving, there's little point in saying anything more.
Create an abstract class, call it something like StringHandler. Give it 2 abstract methods, 1 to check whether the handler can handle the string, then the other to do the processing. Something like:
public abstract class StringHandler
{
public abstract bool CanProcess(string input);
public abstract void Process();
}
public class HelloStringHandler : StringHandler
{
public override bool CanProcess(string input)
{
return input.Equals("hello");
}
public override void Process()
{
Console.WriteLine("HELLO WORLD");
}
}
Then in your main class you can do a simple loop with a list of all known handlers, like
List<StringHandler> handlers = new List<StringHandler>();
handlers.Add(new HelloStringHandler());
string myString = "hello";
foreach (StringHandler handler in handlers)
{
if (handler.CanProcess(myString))
{
handler.Process();
break;
}
}
All this can be optimised/improved obviously, but I hope you get the picture?
I am very rusty at c#, but this was a fun little exercise. The following code is not very clean, but will do what you asked. You will want to add more checks, use the variables better and add more logic, but this should help you get going in the right direction.
var newfile = System.IO.File.CreateText("newcode.txt");
newfile.Write("string[] list = { ");
using (var file = System.IO.File.OpenText("code.txt"))
{
bool bFirst = true;
while (!file.EndOfStream)
{
String line = file.ReadLine();
if (line.Contains("case ") && line.EndsWith(":"))
{
line = line.Replace("case", " ");
line = line.Replace(":", " ");
line = line.Trim();
if (bFirst == false)
{
newfile.Write(", ");
}
bFirst = false;
newfile.Write(line);
}
}
}
newfile.WriteLine(" };");
newfile.Close();
Good luck!
Inspired by #Jheddings answer, I came up with this. Maybe it's over the top, but at least I had fun figuring it out:
Main benefits over jheddings solution:
Uses extension methods, no utility class instance needed.
Reflection lookup of all candidate methods is done only once, right before the first string is evaluated. Afterwards, it is a simple lookup and invoke.
Even simpler usage
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
namespace StringSwitcher
{
class Program
{
static void Main(string[] args)
{
"noAction".Execute(); //No action, since no corresponding method defined
"Hello".Execute(); //Calls Greet method
"world".Execute(); //Calls Shout method
"example".Execute(); //Calls Shout method
Console.ReadKey();
}
//Handles only one keyword
[Keywords("Hello")]
static public void Greet(string s)
{
Console.WriteLine(s + " world!");
}
//Handles multiple keywords
[Keywords("world", "example")]
static public void Shout(string s)
{
Console.WriteLine(s + "!!");
}
}
internal static class ActionBrokerExtensions
{
static Dictionary<string, MethodInfo> actions;
static ActionBrokerExtensions()
{
//Initialize lookup mechanism once upon first Execute() call
actions = new Dictionary<string, MethodInfo>();
//Find out which class is using this extension
Type type = new StackTrace(2).GetFrame(0).GetMethod().DeclaringType;
//Get all methods with proper attribute and signature
var methods = type.GetMethods().Where(
method => Attribute.GetCustomAttribute(method, typeof(KeywordsAttribute)) is KeywordsAttribute &&
method.GetParameters().Length == 1 &&
method.GetParameters()[0].ParameterType.Equals(typeof(string)));
//Fill the dictionary
foreach (var m in methods)
{
var att = (Attribute.GetCustomAttribute(m, typeof(KeywordsAttribute)) as KeywordsAttribute);
foreach (string str in att.Keywords)
{
actions.Add(str, m);
}
}
}
public static void Execute(this string input)
{
//Invoke method registered with keyword
MethodInfo mi;
if (actions.TryGetValue(input, out mi))
{
mi.Invoke(null, new[] { input });
}
}
}
[AttributeUsage(AttributeTargets.Method)]
internal class KeywordsAttribute : Attribute
{
private ICollection<string> keywords;
public KeywordsAttribute(params String[] strings)
{
keywords = new List<string>(strings);
}
public ICollection<string> Keywords
{
get { return keywords; }
}
}
}
Apologies for any strange rendering, for some reason the syntax highlighting chokes on the code :-(

Categories