实现ICompare接口的通用对象比较类
当我们使用Array及ArrayList的Sort方法或BinarySearch方法时,通常需要提供一个实现ICompare接口的类。虽然实现ICompare接口并不复杂但是重复这些写法基本相同的代码,让人感觉到索然无味,那有没有一种通用的方法一劳永逸呢?对于这个问题dannyr兄分享了他的方法《
任意对象数组ArrayList的排序法(可自定义排序字段、排序方向) 》。但是dannyr兄的方法有几个小问题:
- 不能按多个属性或字段排序。
- 如果指定两个对象的属性的值一样(不是两个对象一样),则按这个属性排序后,每排一次对象的位置就变化一下,不稳定。这会对应用到实际的项目中造成困扰。
- 不能指定属性排序时的类型(只能按字符串比较),如作为int来比较。
因此又把自己以前写的代码整理了一下(从实际项目的代码中RIP出来的),帖出来和大家分享。
实现类代码:

/**//// <summary>
/// 通用对象比较类,一般用于对一个对象数组按属性排序或查询
/// </summary>
public class ObjectCompare : System.Collections.IComparer


{
SortEntry[] _sortEntrys;

/**//// <summary>
/// 构造函数,制定排序方法
/// </summary>
/// <param name="type">对象的类型</param>
/// <param name="args">排序方法</param>
public ObjectCompare(Type type, params SortEntry[] args)

{
_sortEntrys = args;
//为防止因为指定的排序字段的值一样而造成每次的排序结果不同,再加属性和字段做为辅助
int j = args.Length;
PropertyInfo[] pis = type.GetProperties(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance);
FieldInfo[] fis = type.GetFields(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance);
_sortEntrys = new SortEntry[_sortEntrys.Length + pis.Length + fis.Length];
args.CopyTo(_sortEntrys, 0);
foreach (PropertyInfo pi in pis)
_sortEntrys[j++] = new SortEntry(pi.Name, pi.PropertyType, false);
foreach (FieldInfo fi in fis)
_sortEntrys[j++] = new SortEntry(fi.Name, fi.FieldType, false);
}

IComparer Members#region IComparer Members
int Compare(object x, object y, string propertyName, Type propertyType)

{
try

{
object sa = GetObjectPropertyValue(x, propertyName);
object sb = GetObjectPropertyValue(y, propertyName);
object ta = sa == DBNull.Value ? null : sa;
object tb = sb == DBNull.Value ? null : sb;
if (null == ta && null == tb)
return 0;
else if (null == ta && null != tb)
return -1;
else if (null != ta && null == tb)
return 1;
else

{
ta = Convert.ChangeType(sa, propertyType);
tb = Convert.ChangeType(sb, propertyType);
return ((IComparable)ta).CompareTo(tb);
}
}
catch

{
throw;
}
}

/**//// <summary>
/// 比较两个对象的大小
/// </summary>
/// <param name="x"></param>
/// <param name="y"></param>
/// <returns>如果对象x大于对象y返回1,对象x小于对象y返回-1,相等则返回0</returns>
public int Compare(object x, object y)

{
try

{
int result;
for (int i = 0; i < _sortEntrys.Length; i++)

{
SortEntry se = _sortEntrys[i];
result = Compare(x, y, se.PropertyName, se.ProeprtyType);
if (se.Descend)
result = -result;
if (0 != result)
return result;
}
//为避免两个对象的属性值一样,再比较他们的hashcode
return x.GetHashCode().CompareTo(y.GetHashCode());
}
catch

{
throw;
}
}
#endregion

public object GetObjectPropertyValue(object obj, string propertyName)#region public object GetObjectPropertyValue(object obj, string propertyName)

/**//// <summary>
/// 得到对象的属性值
/// </summary>
/// <param name="obj">对象名</param>
/// <param name="propertyName">属性名</param>
/// <returns>属性的值,如不存在则反回Null</returns>
public object GetObjectPropertyValue(object instance, string propertyName)

{
try

{
Type t = instance.GetType();
return t.InvokeMember(propertyName,
BindingFlags.GetProperty | BindingFlags.GetField | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance,
null, instance, null);
}
catch

{
throw new Exception(string.Format("未找到属性或字段{0}!", propertyName));
}
}
#endregion
}

/**//// <summary>
/// 排序方式设定
/// </summary>
public struct SortEntry


{

/**//// <summary>
/// 构造函数
/// </summary>
/// <param name="propertyName">属性名</param>
/// <param name="value">是否倒序</param>

public SortEntry(string propertyName) : this(propertyName, typeof(string), false)
{ }

/**//// <summary>
/// 构造函数
/// </summary>
/// <param name="propertyName">属性名</param>
/// <param name="value">是否倒序</param>

public SortEntry(string propertyName, bool isDescend) : this(propertyName, typeof(string), isDescend)
{ }

/**//// <summary>
/// 构造函数
/// </summary>
/// <param name="propertyName">属性名</param>
/// <param name="value">是否倒序</param>
/// <param name="type">属性类型</param>
public SortEntry(string propertyName, Type type, bool isDescend)

{
if (propertyName + "" == "")
throw new Exception("属性名不能为空!");
if (type == null)
throw new Exception("属性的类型不能为空!");
_propertyName = propertyName;
_descend = isDescend;
_type = type;
}

/**//// <summary>
/// 属性名
/// </summary>
string _propertyName;

public string PropertyName
{ get
{ return _propertyName; } set
{ _propertyName = value; } }

/**//// <summary>
/// 是否倒序
/// </summary>
bool _descend;

public bool Descend
{ get
{ return _descend; } set
{ _descend = value; } }
Type _type;

/**//// <summary>
/// 属性的类型
/// </summary>
/// <value></value>

public Type ProeprtyType
{ get
{ return _type; } set
{ _type = value; } }
} 测试代码:
struct Test

{
public Test(string a, int b, string c)

{
A = a;
B = b;
C = c;
}
public string A;
public int B;
public string C;
}
class Program

{
static void Main(string[] args)

{
ArrayList al = new ArrayList();
for (int i = 0; i < 10; i++)

{
al.Add(new Test("A" + i, 1, "1"));
al.Add(new Test("C" + i, 2, "2"));
al.Add(new Test("B" + i, 1, "3"));
al.Add(new Test("A" + i, 3, "4"));
al.Add(new Test("D" + i, 2, "5"));

}

Console.WriteLine("默认排序1");
al.Sort(new ObjectCompare(typeof(Test),new SortEntry("A")));
Output(al);
Console.WriteLine("默认排序2");
al.Sort(new ObjectCompare(typeof(Test)));
Output(al);

Console.WriteLine("按属性A排序1");
al.Sort(new ObjectCompare(typeof(Test),new SortEntry("A")));
Output(al);

Console.WriteLine("按属性A排序2");
al.Sort(new ObjectCompare(typeof(Test),new SortEntry("A")));
Output(al);

Console.WriteLine("按属性B排到序1");
al.Sort(new ObjectCompare(typeof(Test),new SortEntry("B", typeof(int), true)));
Output(al);

Console.WriteLine("按属性B排到序2");
al.Sort(new ObjectCompare(typeof(Test),new SortEntry("B", typeof(int), true)));
Output(al);

Console.ReadLine();
}

static void Output(ArrayList al)

{
foreach (Test obj in al)

{
Console.WriteLine("A:{0}\tB:{1}\tC:{2}", obj.A, obj.B, obj.C);
}
Console.WriteLine("------");
Console.Write("\r\n\r\n\r\n");
}
}