tags:

views:

97

answers:

3

In some of my tests i need to check the order of Lists and do it something like this

DateTime lastDate = new DateTime(2009, 10, 1);
foreach (DueAssigmentViewModel assignment in _dueAssigments)
{
    if (assignment.DueDate < lastDate)
    {
        Assert.Fail("Not Correctly Ordered");
    }
    lastDate = assignment.DueDate;
}

What i would like to do i turn this into an extension method on IEnumerable to make it reusable.

My inital idea was this

public static bool IsOrderedBy<T, TestType>(this IEnumerable<T> value, TestType initalValue)
{
    TestType lastValue = initalValue;
    foreach (T enumerable in value)
    {
        if(enumerable < lastValue)
        {
            return false;
        }
        lastValue = value;
    }
    return true;
}

The ovious problem here is you cant compaire to generic values. Can anyone suggest a way round this.

Cheers Colin

+5  A: 

You could add a restraint:

where T:IComparable

Then instead of using the < operator, you could use the CompareTo() method of the IComparable interface.

Philippe Leybaert
+1  A: 

You should do something like this (I can't see why TestType should be different from T):

public static bool IsOrderedBy<T>(this IEnumerable<T> value, T initalValue)
      where T : IComparable<T> {

      var currentValue = initialValue;

      foreach(var i in value) {
           if (i.CompareTo(currentValue) < 0)
                return false;
           currentValue = i;
      }

      return true;
}
Mehrdad Afshari
+4  A: 

I think it would make more sense to use a method signature similar to the OrderBy method...

public static bool IsOrderedBy<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector)
{
    bool isFirstPass = true;
    TSource previous = default(TSource);

    foreach (TSource item in source)
    {
        if (!isFirstPass)
        {
            TKey key = keySelector(item);
            TKey previousKey = keySelector(previous);
            if (Comparer<TKey>.Default.Compare(previousKey, key) > 0)
                return false;
        }
        isFirstPass = false;
        previous = item;
    }

    return true;
}

You can then use it like that :

List<Foo> list = new List<Foo>();
...

if (list.IsOrderedBy(f => f.Name))
   Console.WriteLine("The list is sorted by name");
else
   Console.WriteLine("The list is not sorted by name");
Thomas Levesque
There's no point in doing that: OrderBy takes a delegate because the value of items might be different from the sort key. In the `IsSorted` case you could simulate that by `Select`:`list.Select(f => f.Name).IsSorted()`
Mehrdad Afshari
Good point... I didn't think of that !
Thomas Levesque
Well, yes, you could always use .Select() then call IsSorted(), but why not just cut out that extra step?
Ryan Versaw
@Ryan: I don't see why one should reinvent the wheel (= more error prone) to reduce something like this. It'll also break the single responsibility principle.
Mehrdad Afshari
As this is for use in unit testing. I have gone with this as the answer. I did not want to inherate from something just for a test. Cheers Thomas
Colin G