I'm dealing with a program that does plenty of if...else branching based on command line arguments. This is in C# but I'm sure it's applicable to Java, C++ etc. Here's the general outline:
if (args.Length == 0)
{
//do something
}
if (args.Length > 0 && args.Length < 2)
{
Console.WriteLine("Only one argument specified. Need two arguments");
return 0;
}
else if (args.Length > 0 && args.Length >= 2)
{
//Process file - Argument 1
if(args[0].Trim() == PROCESS_OPTION_ONE
|| args[0].Trim() == PROCESS_OPTION_TWO)
{
//Process file - Argument 2
if(args[1].Trim() == PROCESS_CUSTOMER
|| args[1].Trim() == PROCESS_ADMIN
|| args[1].Trim() == PROCESS_MEMBER
|| args[1].Trim() == PROCESS_GUEST
|| args[1].Trim() == PROCESS_USER
)
{
So as you can tell, it's kind of a mess. Is there a design pattern or two that would be most applicable toward cleaning things up some? Command pattern, perhaps? Thanks for the advice and tips.
Stop nesting.
You can switch like (+1) Joel said, or you can just break your logic into clear method calls.
if(args.Length <= 1)
{
Console.WriteLine("Need 2 args kthx");
return;
}
if(args.Length > 2)
{
Console.WriteLine("More than 2 args don't know what do");
return;
}
var arg1 = args[0].Trim();
var arg2 = args[1].Trim();
switch(arg1)
{
case PROCESS_OPTION_ONE:
ProcessOptionOne(arg2);
break;
case PROCESS_OPTION_TWO:
ProcessOptionTwo(arg2);
break;
default:
Console.WriteLine("First arg unknown I give up");
return;
}
then, in your process methods...
private static void ProcessOptionTwo(string argumentTwo)
{
if(argumentTwo == PROCESS_CUSTOMER ||
argumentTwo == PROCESS_ADMIN ||
/* etc blah blah */
}
Keep your methods as simple as possible and break up longer, confusing algorithms into distinct method calls which, through their name, give a clear indication of what they are doing.
I'm partial to using switch statements on the arguments array and setting properties in a configuration class of some kind for each anticipated argument. It appears you're expecting a very specifically formatted argument string rather than allowing set values, you could try:
if(args[0].Trim() == PROCESS_OPTION_ONE || args[0].Trim() == PROCESS_OPTION_TWO)
{
//Process file - Argument 2
switch(args[1].Trim()
{
case PROCESS_CUSTOMER, PROCESS_ADMIN, PROCESS_MEMBER, PROCESS_GUEST, PROCESS_USER:
// Do stuff
break;
default:
// Do other stuff
break;
}
}
My preferred method would be something like
foreach(string arg in args)
{
switch(arg)
{
case PROCESS_CUSTOMER:
// Set property
break;
...
default:
// Exception?
break;
}
}
NOTE: args.Length == 1 is faster than args.Length > 0 && args.Length < 2. It's also a little more readable.
You don't need the else if you've already returned. That might cut out a lot of your nesting. You could also try using a switch instead of a bunch of nested ifs.
I took the code from this Code Project article a long time ago and made my own version of it to use for command line applications. I did my own modifications to it, like making the class inherit from Dictionary, etc. But the regex part of the code is very good, and makes these sort of command line switches easy as pie.
Related
I have the following while statement -
while ((!testString.Contains("hello")) && (NewCount != OldCount) && (attemptCount < 100))
{
//do stuff (steps out too early)
}
This is stepping out of the statement even though all the conditions have not been met.
I have tried to reduce it like -
while (!testString.Contains("hello"))
{
// this works and steps out when it should
}
And this steps out when hello is present for example. I also tried changing this to an OR statement which reversed the problem to never stepping out the statement.
Addint the && (NewCount != OldCount) && (attemptCount < 100)) conditions is causing this behaviour how can I resolve this?
This is stepping out of the statement even though all the conditions
have not been met.
To achieve that you need to specify logical OR (||).
For example:
while ((!testString.Contains("hello")) || (NewCount != OldCount) || (attemptCount < 100))
{
//while at least one those conditions is true, loop will work
}
Which means that inside loop you need to introduce security checks, where required, for conditions which are not more true, while loop is still executing.
As an addition to Tigran´s answer. Often (in order to avoid mess with the complex condition) it could be useful to push the condition into the loop:
while (true) { // loop forever unless:
if (testString.Contains("hello")) // ...test string contains "hello"
break;
if (NewCount == OldCount) // ...counts are equal
break;
if (attemptCount >= 100) // ... too many attempts
break;
// ...it's easy to add conditions (as well as comment them out) when you have them
// Loop body
}
I have a (hopefully) simple C# question.
I am parsing arguments in a program where a file will be read from command line, I've allowed for both short and long arguments as input (so for my scenario /f and file are both valid)
The value after either of the above arguments should be the file name to be read.
What I want to do is find this file name in the array based off whichever argument is chosen and copy it in to a string while not leaving any loopholes.
I have functioning code, but I'm not really sure it's "efficient" (and secure).
Code (comments and writes removed):
if ( args.Contains("/f") || args.Contains("file"))
{
int pos = Array.IndexOf(args, "/f");
if (pos == -1)
pos = Array.IndexOf(args, "file");
if (pos > -1)
pos++;
inputFile = (args[pos]);
if (File.Exists(inputFile) == false)
{
Environment.Exit(0);
}
}
Is there a more efficient way to do this, perhaps using some nifty logic in the initial if statement to check which parameter is valid and then do a single check on that parameter?
Using 4 ifs and 2 Array.IndexOf's seems horrible just to support 2 different ways to allow someone to say they want to input a file...
Thanks! And I'm sorry if this seems trivial or is not what SO is meant for. I just don't have any real way to get feedback on my coding practises unfortunately.
Your solution won't scale well. Imagine you have two different arguments with a short and long form. How many conditionals and index checks would that be?
You'd be better off using an existing tool (e.g. Command Line Parser Library) for argument parsing.
One problem I see with the code you provided is that, it will fail if the /f or file is the last argument.
If you don't want to write or use complete argument parsing code, the following code will work slightly better.
var fileArguments = new string[] { "/f", "file" };
int fileArgIndex = Array.FindIndex(args,
arg => fileArguments.Contains(arg.ToLowerInvariant()));
if (fileArgIndex != -1 && fileArgIndex < args.Length - 1)
{
inputFile = args[fileArgIndex + 1];
if (!File.Exists(inputFile))
{
Environment.Exit(0);
}
}
You could write a simple argument parser for your specific need and still have support for "new" scenarios. For example, in your entry method have
// The main entry point for the application.
[STAThread]
static void Main(string[] args)
{
// Parse input args
var parser = new InputArgumentsParser();
parser.Parse(args);
....
}
Where your InputArgumentsParser could be something similar to
public class InputArgumentsParser
{
private const char ArgSeparator = ':';
private Dictionary<string[],Action<string>> ArgAction =
new Dictionary<string[],Action<string>>();
public InputArgumentsParser()
{
// Supported actions to take, based on args
ArgAction.Add(new[] { "/f", "/file" }, (param) =>
Console.WriteLine(#"Received file argument '{0}'", param));
}
/// Parse collection, expected format is "<key>:<value>"
public void Parse(ICollection<string> args)
{
if (args == null || !args.Any())
return;
// Iterate over arguments, extract key/value pairs
foreach (string arg in args)
{
string[] parts = arg.Split(ArgSeparator);
if (parts.Length != 2)
continue;
// Find related action and execute if found
var action = ArgAction.Keys.Where(key =>
key.Contains(parts[0].ToLowerInvariant()))
.Select(key => ArgAction[key]).SingleOrDefault();
if (action != null)
action.Invoke(parts[1]);
else
Console.WriteLine(#"No action for argument '{0}'", arg);
}
}
}
In this case /f:myfile.txt or /file:myfile.txt would spit out to console
Received file argument 'myfile.txt'
This question already has answers here:
Control cannot fall through from one case label
(8 answers)
Closed 9 years ago.
I am trying to convert an if statement to switch cases (for readability)
1) I've read switch statements are aweful in general - Is that true?
https://stackoverflow.com/questions/6097513/switch-statement-inside-a-switch-statement-c
2) The statement goes like this:
switch (Show)
{
case Display.Expense:
if (expected.EXPENSE != true)
break;
case Display.NonExpense:
if (expected.EXPENSE == true)
break;
case Display.All:
//Code
break;
}
Error is:
Control cannot fall through from one case label ('case 1:') to another
This is the original if statement:
if ((Show == Display.All) || (expected.EXPENSE == true && Show == Display.Expense) || (expected.EXPENSE == false && Show == Display.NonExpense))
{
//Code
}
First off, I notice that you forgot to ask a question in your second point. So I'm going to ask some questions for you addressing your second point:
What is the meaning of the "can't fall through" error?
Unlike C and C++, C# does not allow accidental fall-through from one switch section to another. Every switch section must have an "unreachable end point"; it should end with a break, goto, return, throw or (rarely) infinite loop.
This prevents the common bug of forgetting to put in the break and "falling through" accidentally.
You've written your code as though fall-through is legal; my guess is that you're a C programmer.
How can I force fall-through in C#?
Like this:
switch (Show)
{
case Display.Expense:
if (expected.EXPENSE != true)
break;
else
goto case Display.All;
case Display.NonExpense:
if (expected.EXPENSE == true)
break;
else
goto case Display.All;
case Display.All:
//Code
break;
}
Now the reachability analyzer can determine that no matter which branch of the "if" is taken, the switch section endpoint is unreachable.
Is this good style?
No. Your original code was a lot more readable.
I've read switch statements are aweful in general - Is that true?
Opinions vary. Switch statements are very useful when there is a small number of very "crisp" alternatives whose behaviours do not interact in complex ways. Some people will tell you that switched logic should instead be handled by virtual methods or visitor patterns, but that can be abused as well.
Should I use a switch in this particular case?
I wouldn't.
How would you improve my code?
if ((Show == Display.All) ||
(expected.EXPENSE == true && Show == Display.Expense) ||
(expected.EXPENSE == false && Show == Display.NonExpense))
{
//Code
}
First off, don't name things IN ALL CAPS in C#.
Second, don't compare Booleans to true and false. They're already Booleans! If you want to know the truth of statement X you would not say in English "is it true that X is true?" You would say "Is X true?"
I would likely write:
if (Show == Display.All ||
Show == Display.Expense && expected.Expense ||
Show == Display.NonExpense && !expected.Expense)
{
//Code
}
Or, even better, I would abstract the test away into a method of its own:
if (canDisplayExpenses())
{
//Code
}
Or abstract the whole thing away:
DisplayExpenses();
The compiler will not understand what you mean here.
switch (Show)
{
case Display.Expense:
if (expected.EXPENSE != true)
break;
// missing break here
case Display.NonExpense:
The compiler will not connect the dots and understand that the break; statement inside your if statement is linked to the switch statement. Instead it will try to link it to a loop, since break; statements on their own can only be used with loops, to break out of it.
That means that your case block is missing its break statement to complete it, and thus the compiler complains.
Instead of trying to wring the necessary code out of a switch statement, I would instead break up your original if statement.
This is yours:
if ((Show == Display.All) || (expected.EXPENSE == true && Show == Display.Expense) || (expected.EXPENSE == false && Show == Display.NonExpense))
{
//Code
}
This is how I would write it:
bool doDisplayExpected =
(Show == Display.All)
|| (Show == Display.Expense && expected.EXPENSE)
|| (Show == Display.NonExpense && !expected.EXPENSE);
if (doDisplayExpected)
{
// code
}
You don't have to pack everything on one line.
Also, I would try to name properties so that they're easier to read, I would rename the EXPENSE property to IsExpense so that the above code would read like this:
bool doDisplayExpected =
(Show == Display.All)
|| (Show == Display.Expense && expected.IsExpense)
|| (Show == Display.NonExpense && !expected.IsExpense);
if (doDisplayExpected)
{
// code
}
Then, ideally, I would refactor out the sub-expressions to methods:
bool doDisplayExpected =
ShowAll()
|| ShowExpense(expected)
|| ShowNonExpense(expected);
if (doDisplayExpected)
{
// code
}
public bool ShowAll()
{
return Show == Display.All;
}
public bool ShowExpense(Expected expected)
{
return Show == Display.Expense && expected.EXPENSE;
}
public bool ShowNonExpense(Expected expected)
{
return Show == Display.NonExpense && !expected.EXPENSE;
}
Then you can put the expression back into the if-statement:
if (ShowAll() || ShowExpense(expected) || ShowNonExpense(expected))
{
// code
}
This should be easier to read, and change later on.
Use if statements and extract complex conditions into methods, e.g
if (ShowAll() || ShowExpense())
{
}
Remember about OOP and polymorphism every time you write such 'switch', adding another
case to that code will be a nightmare
see this and similar (C++) instructions about converting switches
P.S if you are interested in making your code clean and readable, consider reading Smalltalk Best Practice Patterns by Kent Beck and/or Clean Code by Uncle Bob
I really enjoyed both of them, highly recommend.
If you want readability, just throw away your syntax trash:
if (Show == Display.All || expected.EXPENSE && Show == Display.Expense || !expected.EXPENSE && Show == Display.NonExpense)
{
//Code
}
Provide the else part for each of them so it will not throw error, however as others say, you actually don't need switch in this case.
switch (Show)
{
case Display.Expense:
if (expected.EXPENSE != true)
// do what you want
break;
else
// do what you want
break;
case Display.NonExpense:
if (expected.EXPENSE == true)
// do what you want
break;
else
// do what you want
break;
case Display.All:
//Code
break;
}
The reason why you get this error is that you are not defining break statements.
You defined the break conditionally.
switch (Show)
{
case Display.Expense:
if (expected.EXPENSE != true)
break;
// Note that the break above is in scope of you if statement, and will
// result in a compiler error
case Display.NonExpense:
...
}
Either make sure every case statement has its own break or group the case statements as follows.
switch (Show)
{
case Display.Expense:
case Display.All:
// do stuff
// Expense and All have the same behavior
}
Refactor out the if statements so you can express it like so:
if (isDisplayAll() || isExpense(expected) || isNonExpense(expected))
{
// Code
}
The extracted logic:
private bool isDisplayAll()
{
return (Show == Display.All);
}
private bool IsExpense(Expected expected)
{
return expected.EXPENSE && (Show == Display.Expense);
}
private bool IsNonExpense(Expected expected)
{
return !expected.EXPENSE && (Show == Display.NonExpense);
}
Agree with Dennis, you don't want a switch case for this problem.
Although probably less readable, you can also use shorter:
if (Show == Display.All || (expected.EXPENSE == (Show == Display.Expense)))
{
//Code
}
I am convertng vb.net to c# 2010 as my job, and none of the automatic tools I have can succeed completely. In special example, this case:
'searchString is a string paramter from a long method
Select Case searchString
Case "paid"
'Do something long here
Case "oaaaaa" To "ozzzzzz", "maaaaaa" To "mzzzzzz"
'Do other long code
Case Else
'other long code
End Select
I am mostly java developer before this, so not great with c# and none with vb.net. I do not understand the "oaaaa to ...." part and this part is not converting. Can you please point me to right place to find the c# version of this?
There isn't a direct equivalent in C# but you can easily achieve the same semantics (with more readable code!) using the following:
if(searchString == "paid") {
// do something here
}
else if(
searchString.IsInRange("oaaaaa", "ozzzzzz") ||
searchString.IsInRange("maaaaa", "mzzzzzz")
) {
// do other long code
}
else {
// other long code
}
public static class StringExtensions {
public static bool IsInRange(this string s, string lower, string upper) {
if(String.Compare(lower, upper) > 0) {
throw new InvalidOperationException();
}
return String.Compare(s, lower) >= 0 && String.Compare(s, upper) <= 0
}
There's no direct C# equivalent of the Case "xxx" To "yyy" syntax. I suppose the closest translation will probably be an if/else if/else stack:
if (seachString == "paid")
{
// do something long here
}
else if (((searchString.CompareTo("oaaaaaa") >= 0) && (searchString.CompareTo("ozzzzzz") <= 0))
|| ((searchString.CompareTo("maaaaaa") >= 0) && (searchString.CompareTo("mzzzzzz") <= 0)))
{
// do other long code
}
else
{
// other long code
}
C# doesn't seem to have the concept of Case ... To. See http://msdn.microsoft.com/en-us/library/cy37t14y(VS.80).aspx. The C# example says "This language is not supported".
bitwise has the answer, but here is the translated code (it's just like javascript):
switch (searchString){
case: "paid"
'Do something long here
break;
case: "oaaaaa" To "ozzzzzz", "maaaaaa" To "mzzzzzz"
'Do other long code
break;
default:
'other long code
break;
}
I have one logical question. I have collection of employee objects
There are 3 filter criteria conditions which have handle
For e.g. Employee name, Office name, salary.
Now these filter criteria should match like (Employee name AND/OR Office name AND/OR salary)
So here I have to write (2 raise n) -1 if conditions to handle this situation.
Is there any other way we can do this.
For (Employee name AND/OR Office name) condition I m doing following
if (criteria.EmpName != "" && criteria.OfficeName != "")
{
if (emp.EmpName == criteria.EmpName && emp.OfficeName == criteria.OfficeName)
{
bIsMatch = true;
}
}
else
{
if (criteria.EmpName != "" && emp.EmpName == criteria.EmpName)
bIsMatch = true;
else if (criteria.OfficeName != "" && emp.OfficeName == criteria.OfficeName)
bIsMatch = true;
}
Now if have to handle saraly also i have write min 5 conditions.
Is thr other way to do it?
There are lots of ways to do it, but since you didn't specify one specific language and since I don't feel qualified to judge your coding style, here's one that keeps the general form of your code, while demonstrating some better logic:
bool bIsMatch = true;
if (criteria.EmpName != "" && criteria.EmpName != emp.EmpName) {
bIsMatch = false;
} else if (criteria.OfficeName != "" && criteria.OffIceName != emp.OfficeName) {
bIsMatch = false;
} /* Repeat for as many conditions as there are */
if (bIsMatch) {
/* None of the checks above failed */
}
You can pair up your filtering conditions and have a single statement that encodes all the parameters:
if( (criteria.EmpName.equals("") || criteria.EmpName.equals(emp.EmpName))
&& (criteria.OfficeName.equals("") || criteria.OfficeName.equals(emp.OfficeName))
&& (criteria.Salary.equals("") || criteria.Salary.equals(emp.Salary)))
In each of the AND-ed expressions checks first if the filter is empty, if it is that piece will result in true, if it's not, then the check is performed against the corresponding value in emp and is true only when that check is true.
Start out by assuming you have a match and Then apply each criterion one by one.
bIsMatch = true;
if (bIsMatch && criteria.EmpName != "") bIsMatch = emp.EmpName == criteria.EmpName;
if (bIsMatch && criteria.OfficeName != "") bIsMatch = emp.OfficeName == criteria.OfficeName;
// ...
Or, write a helper function that does the matching.
bool IsMatch(String criterion, String value)
{
return criterion == "" || criterion == value;
}
Then you can do everything in one big if statement:
if (IsMatch(criteria.EmpName, emp.EmpName) &&
IsMatch(criteria.OfficeName, emp.OfficeName) &&
...
)
You can check the criteria individually and maintain a count of matches. That way you need only n conditions:
int matches = 0;
if (criteria.EmpName != "" && emp.EmpName == criteria.EmpName)
matches++;
// similar code for other criteria
if (matches >= 2) { // as many matches as required
// succeeded
}
How about this? The idea scales well for more filters, except that the mapping itself is convention based (name - name).
var map = new Dictionary<string, string>
{
{ criteria.EmpName, emp.EmpName },
{ criteria.OfficeName, emp.OfficeName},
{ criteria.ThirdProp, emp.ThirdProp }
};
bIsMatch = dict.All(kvp => string.IsNullOrEmpty(kvp.Key) || kvp.Key == kvp.Value);
I would question the overall design though; there's something that doesn't seem right about it. How would you deal with the Salary field that you mention? Surely, that's not a string? What's the sentinel-value being used in that case?
Make sure you are clear enough about the business logic before writing the code. According to your code, I can see that you want to check if emp and criteria have the same EmployeeName and OfficeName, any of the properties is considered to be the same if it's string.Empty. The code will be quite clear after yourself is clear. Here we go:
public static bool EmptyOrEquals(this string one, string another)
{
return string.IsNullOrEmpty(another) || one.Equals(another);
}
bIsMatch = emp.EmpName.EmptyOrEquals(criteria.EmpName)
&& emp.OfficeName.EmptyOrEquals(criteria.OfficeName);
Test each question individually and use a bit set to encode the combinations of answers.
This results in cleaner code because you only test each criteria once, it's compact yet readable, and yet you can easily plug in code to handle each combination. And it's the fast too. O(n) to test all the criteria and O(1) to find the actual combination.
For a small, fixed number of criteria, you can push bits around manually. For many criteria, or for a solution that scales, use java.util.BitSet
Bit pushing example:
int bits = 0;
if (...criteria 1...) {
bits = 1;
}
if (...criteria 2...) {
bits |= 2;
}
if (...bits 3...) {
bits |= 4;
}
switch (bits) {
case 0: // no criteria matched
;
case 1: // criteria 1 matched
;
case 2: // criteria 2 matched
;
case 3: // criteria 1 AND 2 matched
;
case 4: // criteria 3 matched
;
case 5: // criteria 1 AND 3 matched
;
case 6: // criteria 2 AND 3 matched
;
case 7: // criteria 1 AND 2 AND 3 matched
;
}
You can generalize this solution using java.util.BitSet to manipulate bits for n criteria (useful when n > 64!). To facilitate quick look up, store the hash of each BitSet combination in a map that maps the hash code to a command class.