I am validating input on a form and attempting to prompt the user of improper input(s) based on the combination of controls used.
For example, I have 2 combo boxes and 3 text boxes. The 2 combo boxes must always have a value other than the first (default) value, but one of three, or two of three, or all text boxes can be filled to make the form valid.
In one such scenario I have a 6 line if statement to try to make the test easily readable:
if ((!String.Equals(ComboBoxA.SelectedValue.ToString(), DEFAULT_COMBO_A_CHOICE.ToString())
&& !String.IsNullOrEmpty(TextBoxA.Text)
&& !String.Equals(ComboBoxB.SelectedValue.ToString(), DEFAULT_COMBO_B_CHOICE.ToString()))
||
(!String.IsNullOrEmpty(TextBoxB.Text)
|| !String.IsNullOrEmpty(TextBoxC.Text)))
{
//Do Some Validation
}
I have 2 questions:
Should this type of if statement be avoided at all cost?
Would it be better to enclose this test in another method? (This would be a good choice as this validation will happen in more than one scenario)
Thanks for your input(s)!
In such a case I find it helps to move some of the logic out of the if statement and into some more meaningfully named booleans. Eg.
bool comboBoxASelected = !String.Equals(ComboBoxA.SelectedValue.ToString(), DEFAULT_COMBO_A_CHOICE.ToString());
bool comboBSelected = !String.Equals(ComboBoxB.SelectedValue.ToString(), DEFAULT_COMBO_B_CHOICE.ToString());
bool textBoxAHasContent = !String.IsNullOrEmpty(TextBoxA.Text);
bool textBoxBHasContent = !String.IsNullOrEmpty(TextBoxB.Text);
bool textBoxCHasContent = !String.IsNullOrEmpty(TextBoxC.Text);
bool primaryInformationEntered = comboBoxASelected && textBoxAHasContent && comboBSelected;
bool alternativeInformationEntered = textBoxBHasContent || textBoxCHasContent;
if (primaryInformationEntered || alternativeInformationEntered)
{
//Do Some Validation
}
Obviously, name the combo and text boxes to reflect their actual content. When someone has to work their way through the logic several months down the line they'll thank you.
a) Doesn't have to necesarily be avoided at all costs. The code works. But it is certainly messy, confusing and I would say could be difficult to maintain.
b) Yes. Give it a relevant name so that the code reader knows what is going on there.
I personally wouldn't have a big issue with code like this. (Your last set of parentheses seem unnecessary.)
Generally, I'd like to keep my if statements simpler. But all your conditions are simple ones. If you really need to test that many tests, then I'd keep it like it is.
It is not very readable yes. But you can shorten it:
!String.Equals(ComboBoxA.SelectedValue.ToString(), DEFAULT_COMBO_A_CHOICE.ToString()
could also be written as:
ComboBoxA.SelectedValue.ToString()!=DEFAULT_COMBO_A_CHOICE
I presume DEFAULT_COMBO_A_CHOICE is already of string to ToString si superflous.
also the parenthese around
(!String.IsNullOrEmpty(TextBoxB.Text)
|| !String.IsNullOrEmpty(TextBoxC.Text))
are not necessary.
IMO such conditions should be avoided (though not at all costs). They are very difficult to read an maintain.
There are several ways of doing that
Try and group the conditions according to the behavior they represent. For example
if (OrderDetailsSelected() && ShippingAddressProvided() )
{
This way you can also avoid the duplication of the conditions within your form.
Secondly, you can use the Boolean Algebra to simplify the expression and
Use Extract Method refactoring to move conditions, which are difficult to read in functions to avoid duplication and make them more readable.
For ex. The condition
String.Equals(ComboBoxB.SelectedValue.ToString(), DEFAULT_COMBO_B_CHOICE.ToString())
can be extracted into a function
private bool IsDefaultA() { return ... }
Related
I'm having a difficult time trying to figure out how to provide certain functionality required for a business application I'm working on.
Basically, we have a string in the DB that contains a conditional statement such as
"(("SomeString.Contains("XYZ") AND SomeString.Contains("VBN")) OR SomeString.Contains("ABC"))"
(This string could contain tons of conditional statements, this is just a simple example).
What I am asked to do is pull that string in from the DB and insert it into an If statement to determine whether or not "SomeString" meets those requirements. "SomeString" will just be a specific string that I will replace once the code is run.
The end result in my mind would be as follows...
if (((SomeString.Contains("XYZ") && SomeString.Contains("VBN")) || SomeString.Contains("ABC")) {
return true;
}
The problem lies in the fact that even if I parse the "AND"s and "OR"s into their code form of "&&"s and "||"s, the value entered into the if statment is still of type string which means the statement will not be treated as a conditional statement.
Is there any way to do this in C#? Libraries or otherwise.
I'm not necessarily looking for someone to write the code for me, I just need a push in the right direction.
Thank you!
I'm looking at some C# source code trying to trace a bug and relying on my basic understanding of programming and msdn to decipher, as I have no experience developing with it. At a key point that the buggy behavior must pass through, I found the following:
public static bool isObjectSpecialCheck(object someObject)
{
string someParam = getParam(someObject);
if (String.IsNullOrEmpty(someParam))
{
someParam = getParamSomewhereElse(someObject);
}
if (!(string.IsNullOrEmpty(someParam)))
{
try
{
if (!string.IsNullOrEmpty(paramIsSpecial(someParam)))
return (true);
else
return (false);
}
catch (System.Exception ex)
{
GlobalConstants.Log(log, "Error", "isObjectSpecialCheck", ex);
return (false);
}
}
return (false);
}
I have swapped out the original variables with dummies to try and keep the question abstract. What I'm noticing is that .isNullOrEmpty is used three distinct ways:
if (String.IsNullOrEmpty(someParam))
if (!(string.IsNullOrEmpty(someParam)))
if (!string.IsNullOrEmpty(paramIsSpecial(someParam)))
The first uses String as the type, first letter capitalized, and does not use a negation.
The second has the negation outside parenthesis and is only passing in a defined variable to the method.
The third has the negation right beside the expression, with the IsNullOrEmpty being passed a function.
So I guess my questions are: Do these distinctions make a difference in general? Do they appear to be required/intentional in the above code? If they do make slight difference but the above choices appear to be style-choices from different contributors, what are the potential logical errors that could result?
The bug I am tracking down might occur if the above always returned true, even when it shouldn't. I'm wondering if 99% of the time the above would return true or false as expected but would return a false true if a specific value were given (maybe 0 or a string literal 'NULL', etc).
Obviously it matters if the negation operator is there or missing. None of the other differences are relevant.
string is simply an alias for System.String. It doesn't matter which you use.
The use of parenthesis around the method call in the second example isn't needed; it is no different than omitting them, as in the third example.
string is an alias for System.String, so there is no difference between those two, similar to how int and Int32 are the same thing.
The negation syntax also does not matter, as it is applying negation to the entire quantity when the extra parentheses are used. Remove it if it is confusing or distracting, leave it in otherwise.
Unfortunately, it sounds like you are going to need to set break points and walk through the code until you find out where the logic is wrong or the data you are processing is wrong. You might also consider putting Console debugging statements in the 3 branches of concern and then viewing the results to see which path(s) are being taken by your data.
One potential issue could be that String.IsNullOrEmpty(str) would return false if str is only whitespace (ex. " "). If your logic is wanting to treat a space as "empty", you would want to trim the string first. It's imposible to tell if this is the actual issue with the limited details you can provide, but something to lookout for none the less.
Currently I'm refactoring my old code, so I have some time to think about how code should look like for somebody else. I managed much of problems, but I always wonder how to prepare good syntax for some nested logical condition. Let's assume that we have following part of code:
bool param1;
int param2;
var result = ( param1 == toCheck.param1) && // to achive condition it always has to be true
((param2 == toCheck.param2)) ||
( (!param1) &&
(param2 == defaultValueForParam2));
// to pass condition param! has to be always true AND ( (params 2 has to be equal) OR (param1 has to be false AND param2 has to be equal with default value)
How should it be formated to be more readable for anybody? Are there some rules of formating conditions? Maybe the general solution is just wrong if I need so complicated condition?
My intention was to ask about: how I should use brackets, how I should use indents, grouping, etc?
If you have a complicated condition, that you cannot make less complicated, it helps to
Have good variable names
Write a small helper function with a clear name so that the calling code is clear
If the conition is used in more that one place Don't Repeat Yourself (see 2.)
Reconsider if you can simplify this. Do you really need boolean flags?
I am try to control multiple strings variables is empty or not at once:
My first approach is very simple:
if(string.isNullOrEmpty(val1) && string.isNullOrEmpty(val2) && string.isNullOrEmpty(val3))
My second way looks like this
if(string.isNullOrEmpty(val1 + val2 + val3))
Which one is fastest and elegant?
Is there any options to do this operation?
The first was faster in my test (just had to): 6ms vs. 70ms and that was on 10,000,000 iterations each (so the speed difference probably doesn't matter very much unless you're doing this on a massive scale).
Anyway, i find the first to be more clear.
Also it doesn't rely on behavior of IsNullOrEmpty that is not immediately obvious (you might just as well think that passing null parameters causes an ArgumentNullException if you don't know better), which i think is important.
Note: The test was with all variables set to null, but setting them to other values confirms it, the longer the strings get, the longer option 2 takes, while option 1 stays at about 30ms max.
Also, the first returns true if any of the strings is null or empty, while the second does it only if all of them are null or empty. So it's not the same check.
They are not equivalent. The first one checks if any of them is null. The second one checks if all of them are null. Make up your mind.
How about this?
new string[] {val1, val2, val2}.All(s => string.IsNullOrEmpty(s))
Or something similar.
I would expect 'fastest' to depend on how often you expect one or more of the strings to actually be null or empty.
For example, if val1 is often going to be null or empty then the first option is likely to be best; if they are all rarely going to be null or empty then I'm not sure of the answer, but it can't take more than five minutes to knock together a few benchmarks for your particular expectations.
(Also, note that the two options don't do the same thing, the first is true if ANY of them are null or empty the second is not doing that)
if(string.isNullOrEmpty(val1 + val2 + val3)) seems to me the fastest
I would advice you to also use concat
but behind the scenes it uses the '+' operator.
I think this is the fastest.
If it werent nullable I suggest summing their length and check ==0
The second one:
if(string.isNullOrEmpty(val1 + val2 + val3))
equals
if(string.isNullOrEmpty(val1) && string.isNullOrEmpty(val2) && string.isNullOrEmpty(val3))
(note the && instead of ||)
but will create an intermediate string, whereas my second version will not create extra strings and stop checking as soon as one string is not empty.
If you have a number of string variables, then I think it is more readable to use the first construction:
if(string.isNullOrEmpty(val1) &&
string.isNullOrEmpty(val2) &&
string.isNullOrEmpty(val3))
{
}
This way, it seems like each variable is treated separately, and this code is a little easier to change if you need to treat one of the variables in another way.
But in case all of the string variables are to be treated in the same way, they are very likely to be represented as an array or another kind of enumeration. Then it's definitely better to use John M Gant's suggestion:
if(myStrings.All(s => string.IsNullOrEmpty(s)))
{
}
Is there a better way for writing a condition with a large number of AND checks than a large IF statement in terms of code clarity?
Eg I currently need to make a field on screen mandatory if other fields do not meet certain requirements. At the moment I have an IF statement which runs over 30 LOC, and this just doesn't seem right.
if(!(field1 == field2 &&
field3 == field4 &&
field5 == field6 &&
.
.
.
field100 == field101))
{
// Perform operations
}
Is the solution simply to break these down into smaller chunks and assign the results to a smaller number of boolean variables? What is the best way for making the code more readable?
Thanks
I would consider building up rules, in predicate form:
bool FieldIsValid() { // condition }
bool SomethingElseHappened() { // condition }
// etc
Then, I would create myself a list of these predicates:
IList<Func<bool>> validConditions = new List<Func<bool>> {
FieldIsValid,
SomethingElseHappend,
// etc
};
Finally, I would write the condition to bring forward the conditions:
if(validConditions.All(c => c())
{
// Perform operations
}
The right approach will vary depending upon details you haven't provided. If the items to be compared can be selected by some sort of index (a numeric counter, list of field identifiers, etc.) you are probably best off doing that. For example, something like:
Ok = True
For Each fld as KeyValuePair(Of Control, String) in CheckFields
If fld.FormField.Text fld.RequiredValue Then
OK = False
Exit For
End If
Next
Constructing the list of controls and strings may be a slight nuisance, but there are reasonable ways of doing it.
Personally, I feel that breaking this into chunks will just make the overall statement less clear. It's going to make the code longer, not more concise.
I would probably refactor this check into a method on the class, so you can reuse it as needed, and test it in a single place. However, I'd most likely leave the check written as you have it - one if statement with lots of conditions, one per line.
You could refactor your conditional into a separate function, and also use De Morgan's Laws to simplify your logic slightly.
Also - are your variables really all called fieldN?
Part of the problem is you are mixing meta data and logic.
WHICH Questions are required(/must be equal/min length/etc) is meta data.
Verifying that each field meets it's requirements is program logic.
The list of requirements (and the fields that apply too) should all be stored somewhere else, not inside of a large if statement.
Then your verification logic reads the list, loops through it, and keeps a running total. If ANY field fails, you need to alert the user.
It may be useful to begin using the Workflow Engine for C#. It was specifically designed to help graphically lay out these sorts of complex decision algorithms.
Windows WorkFlow Foundation
The first thing I'd change for legibility is to remove the almost hidden negation by inverting the statement (by using De Morgan's Laws):
if ( field1 != field2 || field3 != field4 .... etc )
{
// Perform operations
}
Although using a series of && rather than || does have some slight performance improvement, I feel the lack of readability with the original code is worth the change.
If performance were an issue, you could break the statements into a series of if-statements, but that's getting to be a mess by then!
Is there some other relationship between all the variables you're comparing which you can exploit?
For example, are they all the members of two classes?
If so, and provided your performance requirements don't preclude this, you can scrape references to them all into a List or array, and then compare them in a loop. Sometimes you can do this at object construction, rather than for every comparison.
It seems to me that the real problem is somewhere else in the architecture rather than in the if() statement - of course, that doesn't mean it can easily be fixed, I appreciate that.
Isn't this what arrays are basically for?
Instead of having 100 variables named fieldn, create an array of 100 values.
Then you can have a function to loop combinations in the array and return true or false if the condition matches.