When the object in the list does not implement IComparable interface the generic methods OrderBy() or ThenBy() fail only at run time. Like in this example:
public class DataClass
{
public int Value { get; set; }
public DataClass(int value)
{
Value = value;
}
}
void Test()
{
var list = new List<DataClass>() { new DataClass(10), new DataClass(1), new DataClass(5) };
var sortedList = list.OrderBy(data => data).ToList(); // InvalidOperationException thrown by OrderBy()
}
Is there a way to detect this problem at compile time?
By detecting the problem I mean compiler showing me the error that the lambda function used in OrderBy() call does not return the object implementing IComparable interface. I want to see the compile time error instead of a run-time one.
I am looking for the least expensive fix here ordered by ease of implementation:
As I was answering this, I think I may have found a reason why this constraint doesn't exist: the type of Key
in the keySelector
can implement either IComaprable<TKey>
or IComparable
, and I there isn't any way to use OR in a constraint!
So, given that information, if you wanted to write your own extension method to add the type constraint, you'd either have to write two of them (with different names) for each overload, or you'd just have to choose which interface to constrain the TKey
type to.
If that's acceptable, then read on for my original answer...
I think the only way you can get a compile-time error for this method is to wrap it in your own extension method where you add the IComparable<T>
constraint before calling the Linq
method:
public static class Extensions
{
public static IEnumerable<TSource> OrderByConstrained<TSource, TKey>(
this IEnumerable<TSource> source, Func<TSource, TKey> keySelector)
where TKey : IComparable<TKey>
{
return source.OrderBy(keySelector);
}
}
And now you'll get a compile time error until the Data
class implements IComparable<DataClass>
:
var sortedList = list.OrderByConstrained(data => data);
// Compile Error CS0311: The type 'Test.Program.DataClass' cannot be used as type
// parameter 'TKey' in the generic type or method
// 'Extensions.OrderByConstrained<TSource, TKey>
// (IEnumerable<TSource>, Func<TSource, TKey>)'.
// There is no implicit reference conversion from 'Test.Program.DataClass' to
// 'System.IComparable<Test.Program.DataClass>'.
And then implementing the interface will resolve the compile error:
public class DataClass : IComparable<DataClass>
{
public int Value { get; set; }
public DataClass(int value)
{
Value = value;
}
public int CompareTo(DataClass other)
{
return other == null ? 1 : Value.CompareTo(other.Value);
}
}