一,通常我们自己定义一个类,然后对类的集合进行排序,是下面这样的做法
class People { public int ID { get; set; } public string Name { get; set; } public DateTime Birthday { get; set; } public override string ToString() { return string.Format("{0},{1},{2}", ID, Name, Birthday); } }
再定义一个类继承IComparer<People>接口
/// <summary> /// user define /// </summary> class PeopleCompare : IComparer<People> { #region IComparer<People> public int Compare(People x, People y) { return Comparer<int>.Default.Compare(x.ID, y.ID); } #endregion }
调用代码:
public static void TestFunc() { var peoples = new People[] { new People{ID = 1,Name = "a123",Birthday = new DateTime(2000,05,01)}, new People{ID = 4,Name = "b123",Birthday = new DateTime(2000,04,01)}, new People{ID = 2,Name = "d123",Birthday = new DateTime(2000,02,01)}, new People{ID = 3,Name = "e123",Birthday = new DateTime(2000,04,01)}, }; Array.Sort(peoples, new PeopleCompare()); peoples.ForEach<People>(p => System.Diagnostics.Debug.WriteLine(p)); }
结果输出如下:
1,a123,2000/05/01 0:00:00 2,d123,2000/02/01 0:00:00 3,e123,2000/04/01 0:00:00 4,b123,2000/04/01 0:00:00
二,如果我们又定义了Cat,Monkey等等这样的类,就得每次都写一个类似于PeopleCompare的类,当然你也可以在定义People的时候继承Icomparable接口,本文不讨论。
这样做有大量的重复工作,现在考虑定义一个泛型的方法来创建通用的继承了IComparer的类,并且考虑到类有多个字段,对多个字段的排序也考虑进去。下面的这个类定义了一个最大支持4个字段的ComparerFactory类,一般应用已经足够了。
/// <summary> /// Common Comaparer Generate Class, supported 4 paramers limitted /// </summary> /// <typeparam name="T"></typeparam> public static class ComparerFactroy<T> { public static IComparer<T> Create<V1>(Func<T, V1> keySelector1) { return new MyCommonComparer<V1, Object, Object, Object>(keySelector1,Comparer<V1>.Default,null,null,null, null, null, null); } public static IComparer<T> Create<V1, V2>(Func<T, V1> keySelector1, Func<T, V2> keySelector2) { return new MyCommonComparer<V1, V2, Object, Object>(keySelector1,Comparer<V1>.Default, keySelector2,Comparer<V2>.Default,null,null, null, null); } public static IComparer<T> Create<V1, V2, V3>(Func<T, V1> keySelector1, Func<T, V2> keySelector2, Func<T, V3> keySelector3) { return new MyCommonComparer<V1, V2, V3, Object>(keySelector1, Comparer<V1>.Default, keySelector2, Comparer<V2>.Default, keySelector3, Comparer<V3>.Default, null,null); } public static IComparer<T> Create<V1, V2, V3,V4>(Func<T, V1> keySelector1, Func<T, V2> keySelector2, Func<T, V3> keySelector3, Func<T, V4> keySelector4) { return new MyCommonComparer<V1, V2, V3, V4>(keySelector1, Comparer<V1>.Default, keySelector2, Comparer<V2>.Default, keySelector3, Comparer<V3>.Default, keySelector4,Comparer<V4>.Default); } class MyCommonComparer<V1,V2,V3,V4> : IComparer<T> { Func<T, V1> keySelector1; Func<T, V2> keySelector2; Func<T, V3> keySelector3; Func<T, V4> keySelector4; IComparer<V1> comparer1; IComparer<V2> comparer2; IComparer<V3> comparer3; IComparer<V4> comparer4; public MyCommonComparer(Func<T, V1> keySelector1, IComparer<V1> compare1, Func<T, V2> keySelector2, IComparer<V2> compare2, Func<T, V3> keySelector3, IComparer<V3> compare3, Func<T, V4> keySelector4, IComparer<V4> compare4) { this.keySelector1 = keySelector1; this.keySelector2 = keySelector2; this.keySelector3 = keySelector3; this.keySelector4 = keySelector4; this.comparer1 = compare1; this.comparer2 = compare2; this.comparer3 = compare3; this.comparer4 = compare4; } #region IComparer<T> メンバ public int Compare(T x, T y) { int retVal = 0; if (keySelector1 != null) retVal = comparer1.Compare(keySelector1(x), keySelector1(y)); if (keySelector2 != null && retVal == 0) retVal = comparer2.Compare(keySelector2(x), keySelector2(y)); if (keySelector3 != null && retVal == 0) retVal = comparer3.Compare(keySelector3(x), keySelector3(y)); if (keySelector4 != null && retVal == 0) retVal = comparer4.Compare(keySelector4(x), keySelector4(y)); return retVal; } #endregion } }
ComparerFactory的Create方法根据你传的类型,创建一个Comparer,Create方法有4个重载,可以对1,2,3,4个字段进行排序。
继续用上面定义的People类测试,使用方法如下:
public static void TestFunc() { var peoples = new People[] { new People{ID = 1,Name = "a123",Birthday = new DateTime(2000,05,01)}, new People{ID = 4,Name = "b123",Birthday = new DateTime(2000,04,01)}, new People{ID = 2,Name = "d123",Birthday = new DateTime(2000,02,01)}, new People{ID = 3,Name = "e123",Birthday = new DateTime(2000,04,01)}, new People{ID = 3,Name = "e123",Birthday = new DateTime(2000,03,01)}, new People{ID = 3,Name = "c123",Birthday = new DateTime(2000,03,01)} }; Array.Sort(peoples, ComparerFactroy<People>.Create(p => p.ID, p => p.Name, p => p.Birthday)); peoples.ForEach<People>(p => System.Diagnostics.Debug.WriteLine(p)); }
分别根据People的ID,Name,Birthday进行排序
测试结果:
1,a123,2000/05/01 0:00:00 2,d123,2000/02/01 0:00:00 3,c123,2000/03/01 0:00:00 3,e123,2000/03/01 0:00:00 3,e123,2000/04/01 0:00:00 4,b123,2000/04/01 0:00:00
可以继续完善的地方:
1,现在默认是每个字段的升序排列,可以在参数中每个字段的升序降序排列。
2,现在只支持4个字段,扩充字段代码改动较大,不知道还有没有更好的支持多字段的写法,欢迎一起讨论。