tags:

views:

109

answers:

6

I was looking at a piece of code I wrote in C#:

if(string.IsNullOrEmpty(param1) && string.IsNullOrEmpty(param2) && string.IsNullOrEmpty(param3))
{
       // do stuff
}

and decided to make it more readable/concise

if(string.IsNullOrEmpty(param1+param2+param3))
{
       // do stuff
}

But looking at it I can't help but cringe. What are your thoughts on this? Have you ever done something like this and do you use it whenever applicable.

Note: The code previous to this line would manipulate a collection by adding specific items depending on if the a param (param1,param2,param3) is NOT empty. This if statement is meant for validation/error handeling.

A: 

The original code, though longer, is more clear in its intent, and likely similar performance-wise. I'd leave it alone.

Michael Petrotta
+1  A: 

If you can get the params in a collection (which if it's function you can with the params keyword) then this might work:

if (myParams.Any(IsNullOrTrimEmpty)
    {
        // do stuff
    }

The example uses this string extension and myParams is a string[].

cottsak
You can just to myParams.Any(String.IsNullOrEmpty)
ICR
@ICR: Can you explain that in more detail?
cottsak
@ ICR- I think he meant p.IsNullOrTrimEmpty() is from that extension method, not the .Any()
Baddie
yeh that's what i suggested right? your 1st comment is syntactically incorrect. the `IsNullOrEmpty` function requires a parameter.
cottsak
@cottsak My example is correct, just not what you meant. Any takes a function which takes one argument, String.IsNullOrEmpty is a function which takes one argument thus it can be passed to Any.
ICR
Also, if you're using .NET 4.0 you can use the new IsNullOrWhitespace in place of the custom IsNullOrTrimEmpty extension method.
ICR
i understand your example now. that's why you omitted the '()'. nice shortcut!
cottsak
+1 for your link to extension methods.
Roman Boiko
+2  A: 

That won't work. If any of the strings are null, you'll get a null dereference exception. You need to check them before you use them.

In addition, it's very inefficient. You are concatenating all the strings into a new string, then test if this is non-empty. This results in one or more memory allocations and potentially a lot of data being copied, only to be immediately thrown away and garbage collected a moment later.

A better approach is to write a method that takes variable arguments or a list of strings and checks them one by one using IsNullOrEmpty in a loop. This will be more efficient, safe, but still achieve the desired result of tidy code in your if statement.

Jason Williams
Concatenating null strings does not result in a NullReferenceException. Only dereferencing them does.
Michael Petrotta
Agree with Michael. Yes, it will be inefficient - but it won't throw.
Jon Skeet
I'm glad I answered - I like it when I learn something new :-) Any chance you can stop downvoting me now? It's still inefficient.
Jason Williams
Creating a list of strings would be inefficient too, of course - it may well be about as inefficient as concatenating the strings. In fact, it may be *more* inefficient - it would have to create at least two objects (the list itself, and the array within the list).
Jon Skeet
Yes - it would depend primarily on the average length of the param strings. I'd just stick with the original (multiple IsNullOrEmpty) checks myself.
Jason Williams
@Jon: I only suggested the array in the event that it was the initial form. I inferred it i guess from the example in the question. Sure i wouldn't suggest creating an array of strings from explicitly defined variables in local scope. That's a waste.
cottsak
@Jon: concatenating the strings will likely result in more copies than the list and array within the list though, especially if you call the method with large strings. the list only holds references, whereas the concatenation results in string copies.
Sander Rijken
As addition to the previous comment, I don't suggest creating a list. If there's 3 params that need to be checked for null, check them individually like the first example in the question
Sander Rijken
+3  A: 

Personally I prefer the former over the latter. To me the intent is more explicit -- checking if all parameters are null/empty.

The second also hides the fact it does handle nulls. Null strings are odd. Jason Williams above, for example, didn't relise that it does in fact work.

ICR
I was also surprised that concatenating null string references didn't throw.
Michael Burr
+1 for explicitness (i think that is a word) - the code is not as easily understood in the 2nd example
cottsak
+1 for correct validation. In second example validation would pass even if **some** (not all) of strings were null or empty. This would change behavior. And the main purpose was validation, as Buddie explicitly wrote. Thus the latter example introduced a bug.
Roman Boiko
@Roman Boiko Would it change the behaviour? Surely even if some of the strings were empty or empty they are appended to a non-null-non-empty string resulting in a non-null-non-empty string, and thus the condition IsNullOrEmpty would fail.
ICR
+2  A: 

Maybe write it something like this, which is a bit more readable:

bool paramsAreInvalid =
   string.IsNullOrEmpty(param1)
   && string.IsNullOrEmpty(param2)
   && string.IsNullOrEmpty(param3);

if (paramsAreInvalid)
{
       // do stuff
}
cxfx
+3  A: 

It's a small thing, but I think a minor reformatting of your original results in improved readability and makes the intent of the code about as crystal clear as can be:

if ( string.IsNullOrEmpty(param1) && 
     string.IsNullOrEmpty(param2) && 
     string.IsNullOrEmpty(param3) )
{
       // do stuff
}

Consider this similar set of examples:

if ( c == 's' || c == 'o' || c == 'm' || c == 'e' || c == 't' || c == 'h' || c == 'i' || c == 'n' || c == 'g') {
    // ...
}

if ( c == 's' || 
     c == 'o' || 
     c == 'm' || 
     c == 'e' || 
     c == 't' || 
     c == 'h' || 
     c == 'i' || 
     c == 'n' || 
     c == 'g') {
    // ...
}
Michael Burr