16
\$\begingroup\$

I have to loop through a list of strings and validate that all are parsable to int and not less than 1. Also, if a string is not parsable but is null or whitespace, then it is OK and my validator should not fail.

Here's the code I have come up with which works fine but leads to method complexity:

public static bool ArePerPersonBILimitsInvalid(IEnumerable<string> bilimits)
        {
            return bilimits.Any(c =>
            {
                int d;
                if (!int.TryParse(c, out d))
                {
                    if (string.IsNullOrWhiteSpace(c))
                    {
                        return false;
                    }

                       return true;
                }

                if (d < 1)
                {
                    return true;
                }

                return false;
            });
        }
\$\endgroup\$

4 Answers 4

19
\$\begingroup\$

I find that negatives in method names lead to confusing code. For instance,

if (!ArePerPersonBILimitsInvalid(...))

"Are there no BI limits that are invalid?"

becomes much more readable when we write it this way:

if (ArePerPersonBILimitsValid(...))

"Are all BI limits valid?"

So let's fill in the blanks.

public static bool ArePerPersonBILimitsValid(IEnumerable<string> biLimits)
{
    return biLimits.All(IsBILimitValid);
}

Great, so now we need to write IsBILimitValid.

public static bool IsBILimitValid(string biLimit)
{
    if (string.IsNullOrWhiteSpace(biLimit))
    {
        return true;
    }

    int value;
    return int.TryParse(biLimit, out value) && value >= 1;
}

This way the code much more closely reflects your problem statement:

loop through a list of strings and validate that all are parsable to int and not less than 1

\$\endgroup\$
6
  • \$\begingroup\$ @Heslacher, no I meant "more readable (when written) as"... perhaps I should have said, "is less readable than". \$\endgroup\$
    – mjolka
    Commented Aug 8, 2014 at 5:27
  • \$\begingroup\$ Still a "negative" with !int.TryParse. I'd go with return int.TryParse(biLimit, out value) && value >= 1; but it's debatable, if that's more readable. \$\endgroup\$
    – Corak
    Commented Aug 8, 2014 at 5:53
  • \$\begingroup\$ @Corak that's a nice version, mind if I use that in my answer? My note about negatives was just in relation to method names, e.g. IsValid vs IsInvalid, HasErrors vs HasNoErrors. \$\endgroup\$
    – mjolka
    Commented Aug 8, 2014 at 5:55
  • \$\begingroup\$ @mjolka - not at all ^_^. I try to avoid the !something notation wherever possible (and feasible), because it's so easy to miss the !. I even use something == false sometimes to really make it obvious (but of course, never ever something == true). \$\endgroup\$
    – Corak
    Commented Aug 8, 2014 at 6:02
  • 1
    \$\begingroup\$ @dreza thanks, I thought it was clear but getting two questions on that point meant it wasn't! I've tried to improve the wording. \$\endgroup\$
    – mjolka
    Commented Aug 8, 2014 at 23:01
7
\$\begingroup\$

As per my interpretation, you don't need empty string check inside the if clause you can put it out side, and last condition could be expressed in one line.

return bilimits.Any(inputstring =>
{
    if (string.IsNullOrWhiteSpace(inputstring))
        return false;

    int parsedNumber;
    if (!int.TryParse(inputstring, out parsedNumber))
        return true;

    return parsedNumber < 1;
});
\$\endgroup\$
2
\$\begingroup\$

I don't think it's that really bad, but you could simplify it by doing it all in one statement.

public static bool ArePerPersonBILimitsInvalid(IEnumerable<string> bilimits)
{
    return bilimits.Any(c =>
    {
        int asInt;
        return (int.TryParse(c, out asInt) && asInt < 1) ||
                !string.IsNullOrWhiteSpace(c);
    });
}

Some of the other answers I actually like. I'll just provide this as an alternative.

\$\endgroup\$
2
  • 1
    \$\begingroup\$ You don't need to initialize asInt, it's definitely assigned in all code after TryParse(). \$\endgroup\$
    – svick
    Commented Aug 8, 2014 at 13:45
  • \$\begingroup\$ @svick true, just habit I think. \$\endgroup\$
    – dreza
    Commented Aug 8, 2014 at 19:22
0
\$\begingroup\$
public static bool ArePerPersonBILimitsValid(this IEnumerable<string> biLimits)
{
    int intResult;
    var invalidResults = biLimits.Where(s => {
            if (int.TryParse(s, out intResult))
                return false;
            else
                return !string.IsNullOrWhiteSpace(s);
        });
    return invalidResults.Count() == 0;
}

string[] inValidTestIntegers = new string[] { "10", "12", "str" });
string[] balidTestIntegers = new string[] { "10", "12" });
bool isValid1 = inValidTestIntegers.ArePerPersonBILimitsValid();
bool isValid2 = balidTestIntegers.ArePerPersonBILimitsValid();

//output: false true

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.