This feels like a too easy question to be found with google, I think/hope I’ve got stuck in the details when trying to implement my own version of it. What I’m trying to do is to sort a list of MyClass objects depending on my Datatype object different search functions should be used.
I’ve had something like this in mind for the class Datatype:
class Datatype {
public delegate int CMPFN(object x, object y);
private CMPFN compareFunction;
(...)
private XsdDatatype((...), CMPFN compareFunction) {
(...)
this.compareFunction = compareFunction;
}
public CMPFN GetCompareFunction() {
return this.compareFunction;
}
static private int SortStrings(object a, object b) {
return ((MyClass)a).GetValue().CompareTo(((MyClass)b).GetValue());
}
}
And later on I’m trying to sort a MyClass list something like this:
List<MyClass> elements = GetElements();
Datatype datatype = new Datatype((...), Datatype.SortStrings);
elements.Sort(datatype.GetCompareFunction()); // <-- Compile error!
I’m not overly excited about the cast in Datatype.SortStrings but it feels like this could work(?). The compiler however disagrees and gets me this error on the last line above and I’m a bit unsure exactly why CMPFN can’t be converted/casted(?) to IComparer.
Cannot convert type 'proj.Datatype.CMPFN' to 'System.Collections.Generic.IComparer<proj.MyClass>'
Delegates aren’t duck-typed like that. You can create an
Comparison<MyClass>from aCMPFNbut you can’t use a plain reference conversion – either implicit or explicit.Three options:
Create the comparer like this:
Use a lambda expression to create a
Comparison<T>and use that instead:Write an implementation of
IComparer<MyClass>which performs the comparison based on aCMPFNNote that the second approach will call
GetCompareFunctiononce per comparison.A much better solution would be to get rid of
CMPFNentirely – why not just use (or implement)IComparer<MyClass>to start with? Note that that would remove the casts as well. (If you’re happy using delegates instead of interfaces, you could express the comparison as aComparison<MyClass>instead.)Note that as of .NET 4.5, you can use
Comparer.Createto create aComparer<T>from aComparison<T>delegate.I’m not sure why your current API is in terms of
object, but you should be aware that in C# 3 and earlier (or C# 4 targeting .NET 3.5 and earlier) you wouldn’t be able to convert anIComparer<object>into anIComparer<MyClass>(via a reference conversion, anyway). As of C# 4 you can, due to generic contravariance.