I'm working with a library (TreeView in Gtk to be specific) that allows you to sort by passing a function that compares two rows. A simplified version of the function signature might look like this:
int SomeSortFunc (Foo foo1, Foo foo2)
{
// Return -1 if foo1 < foo2, 0 if foo1 ==开发者_运维知识库 foo2, 1 if foo1 > foo2
}
I can't simply implement Foo.CompareTo (Foo)
, because I want to sort differently depending on the context. There are several fields in Foo
that I sort by. The sort priority of each field is what depends on the context. I would like to write something like this:
int SortFunc<T> (Foo foo1, Foo foo2, params Func<Foo, T> [] selectors)
where T : IComparable<T>
{
return selectors
.Select (s => s (foo1).CompareTo (s (foo2)))
.FirstOrDefault (i => i != 0);
}
// Compare by SomeString, then by SomeInt, then by SomeBar
int SomeSortFunc (Foo foo1, Foo foo2)
{
// Won't compile, because String, Int, and Bar are all different types.
return SortFunc (foo1, foo2, f => f.SomeString, f => f.SomeInt, f => f.SomeBar);
}
This won't compile, because the T
in Func<Foo, T>
is different for String
, Int
, and Bar : IComparable<Bar>
(in other words, there is no way to resolve the T
in SortFunc<T>
).
Is there any way to write this function such that each selector can return a different type, as long as each type SomeType
implements IComparable<SomeType>
?
I would simplify it and just accept a function returning a non-generic IComparable
. Now you can pass in functions returning primitives without needing to figure out the number of generic type parameters your function would actually need, as it would truthfully need type parameters for each of the functions provided.
int SortFunc(Foo foo1, Foo foo2, params Func<Foo, IComparable>[] selectors)
精彩评论