Verifying that all elements in a collection satisfy some condition

Feb 16, 2011 at 11:30 PM

Hi folks,

i currently have the following code .. can it be refactored, better? (using .NET 4.0 btw).

Condition.Requires(someCollection)
                .IsNotNull()
                .IsNotEmpty()
                .Evaluate(someCollection.Select(x => x.SomeId).ToList().All(y => y > 0));
i'm seeing we have a collection that is not empty AND for each item in that collection, the Id is > 0.

Coordinator
Feb 17, 2011 at 8:10 AM
Edited Feb 18, 2011 at 5:00 AM

You can start by rewriting the evaluation as follows:

 

Condition.Requires(someCollection)
    .IsNotNull()
    .IsNotEmpty()
    .Evaluate(someCollection.All(i => i.SomeId > 0));

But an new extension method would perhaps even be more appropriate. I'll get back on that later. (to be continued)

Feb 17, 2011 at 9:32 AM

OOO! i tried that but failed.. i wonder what i did wrong. maybe  i did Any(,..) accidently.

/me holds his breath for the To Be Continued part ... :) *Woot*

Coordinator
Feb 17, 2011 at 7:54 PM
Edited Feb 17, 2011 at 7:55 PM

Here is part 2. You can add the following extension methods to your project(s):

public static ConditionValidator<IEnumerable<TElement>> ContainsAll<TElement>(
    this ConditionValidator<IEnumerable<TElement>> validator, Predicate<TElement> predicate)
{
    var collection = validator.Value;

    if (predicate == null || (collection != null && !collection.All(predicate)))
    {
        validator.ThrowException("all elements of " + validator.ArgumentName +
            " should satisfy the given condition");
    }

    return validator;
}
public static ConditionValidator<IEnumerable<TElement>> ContainsAll<TElement>(
    this ConditionValidator<IEnumerable<TElement>> validator, Predicate<TElement> predicate,
    string conditionDescription)
{
    var collection = validator.Value;

    if (predicate == null || (collection != null && !All(collection, predicate)))
    {
        validator.ThrowException(conditionDescription);
    }

    return validator;
}

Using these extension methods will allow you to do the following:

Condition.Requires(someCollection)
    .IsNotEmpty()
    .ContainsAll(i => i.SomeId > 0);

There is however, one little caveat here. Due to the limits of type inference in C#, these methods will only work when the someCollection is exactly of type IEnumerable<T>. When someCollection is defined as T[], IList<T>, ICollection<T> etc., the code will not compile. You can get this to work as follows:

Condition.Requires(someCollection.AsEnumerable())
    .IsNotEmpty()
    .ContainsAll(i => i.SomeId > 0);

Because this behavior is a bit awkward and counterintuitive, I'm not able to add this method as extension method to the library, which is unfortunate. The covariance and contravariance support of .NET 4.0 would solve this, but this would also force the API to change (because the Requires() and Ensures() method would have to return an interface of type IConditionValidator<out T>).

I hope this helps.

Feb 17, 2011 at 11:33 PM

Sure does mate :) Love your work and cheers :)