It's been a long time since making this class and don't believe I posted it yet, but since I'm going to use it in the DataGridViewGrouper (see previous post), thought I'd post it now.
Since it's “older” code, it's fully .net 2.0 compatible. It can be uses where ever an IComparer interface is used. (or the Compare function of the GenericComparer<> class for a Comparison<> call)
Usage example:
Array.Sort(YourArray, new GenericComparer());
There is a generic comparer class already in the framework, but it will fail on certain types. It's been a while, but I believe the .net native class doesn't support the Nullable struct and strong implementers of the generic IComparer<> interface. (The new Linq will fail if the object sorted on is not an IComparable)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;
using System.ComponentModel;
namespace Subro
{
///
<summary>
/// Comparer that tries to find the 'strongest' comparer for a type.
/// if the type implements a generic IComparable, that is used.
/// otherwise if it implements a normal IComparable, that is used.
/// If neither are implemented, the ToString versions are compared.
/// INullable structures are also supported.
/// This way, the DefaultComparer can compare any object types and can be used for sorting any source.
/// </summary>
/// <example>Array.Sort(YourArray,new GenericComparer());</example>
public class GenericComparer :
IComparer{
public GenericComparer()
{
}
public GenericComparer(
Type Type)
{
this.Type = Type;
}
Type type;
public Type Type
{
get
{
return type;
}
set
{
if (value == null) throw new ArgumentNullException();
type = value;
comp = null;
} }
Type targettype;
/// <summary>
/// normally the same as the type, but can be set to a different type
/// </summary>
public Type TargetType
{
get
{
if (targettype == null) return type;
return targettype;
}
set
{
if (TargetType == value) return;
targettype = value;
comp = null;
} }
IComparer comp;
IComparer GetGenericComparer(
Type From,
Type To)
{
while (To !=
typeof(
object))
{
if (
typeof(
IComparable<>).MakeGenericType(To).IsAssignableFrom(From))
return (IComparer)Activator.CreateInstance(typeof(StrongCompare<,>).MakeGenericType(From,To));
To = To.BaseType; }
return null; }
public
IComparer GetComparer(
Type From,
Type To)
{
var gen = GetGenericComparer(From,To);
if (gen !=
null)
return gen;
else if (
typeof(
IComparable).IsAssignableFrom(type))
{
return (IComparer)Activator.CreateInstance(typeof(NonGenericCompare<>).MakeGenericType(type));
}
else if (type.IsGenericType && typeof(Nullable<>) == type.GetGenericTypeDefinition())
{
var basetype = type.GetGenericArguments()[0];
return (
IComparer)
Activator.CreateInstance(
typeof(
NullableComparer<>).MakeGenericType(basetype),
GetComparer(basetype, To == From ? basetype : To));
}
return new StringComparer(); }
class
NullableComparer<T>:
IComparer
where T:struct
{
public
readonly IComparer BaseComparer;
public NullableComparer(
IComparer BaseComparer)
{
this.BaseComparer = BaseComparer;
}
object getval(
object o)
{
return ((Nullable<T>)o).Value;
}
public
int Compare(
object x,
object y)
{
return BaseComparer.Compare(getval(x), getval(y));
}
}
class
StrongCompare<F,T> :
IComparer
where F : IComparable<T>
{
public
int Compare(
object x,
object y)
{
return ((F)x).CompareTo((T)y);
} }
class
NonGenericCompare<T> :
IComparer
where T: IComparable
{
public
int Compare(
object x,
object y)
{
return ((T)x).CompareTo(y);
} }
class
StringComparer :
IComparer{
public
int Compare(
object x,
object y)
{
return x.ToString().CompareTo(y.ToString());
} }
public
bool Descending
{
get
{
return factor < 0;
}
set
{
factor = value ? -1 : 1;
} }
int factor = 1;
int compare(
object x,
object y)
{
if (x == y)
return 0;
if (x ==
null)
return -1;
if (y ==
null)
return 1;
if (type ==
null)
Type = x.GetType();
if (comp ==
null)
comp = GetComparer(type, TargetType);
return comp.Compare(x, y);
}
public
int Compare(
object x,
object y)
{
return factor * compare(x, y);
}
}
public class GenericComparer<T> : GenericComparer,IComparer<T>
{
public GenericComparer()
: base(typeof(T))
{ }
public
int Compare(T a, T b)
{
return base.Compare(a, b);
}
}
public
class PropertyDescriptorComparer :
GenericComparer{
public readonly PropertyDescriptor Prop;
public PropertyDescriptorComparer(
PropertyDescriptor Prop)
: this(Prop, true)
{
}
public PropertyDescriptorComparer(
PropertyDescriptor Prop,
bool Descending)
: base(Prop.PropertyType)
{
this.Prop = Prop;
this.Descending = Descending;
}
}
public
static partial class Extend{
public
static void Sort<T>(
this List<T> list,
Func<T, T,
int> Comparer)
{
list.Sort(new Comparison<T>(Comparer));
}
///
<summary>
/// Sort on a property or field
/// </summary>
public static void Sort<T, S>(
this List<T> list,
Func<T, S> Property)
{
var c = new Subro.GenericComparer<S>();
Sort(list, (t1, t2) => c.Compare(Property(t1), Property(t2)));
}
}
}
. . .