自定义泛型集合,完成一些自己想要的操作
1.自定义的泛型集合类TravelList.cs,可以根据需要筛选方法
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Collections; using System.Reflection; using System.ComponentModel; namespace CustomList { [Serializable] public class TravelList<T> : IEnumerable<T> { private List<T> innerList; //内部所使用的List,集合成员保存在这里. /// <summary> /// 集合描述,用于存储一些附带信息。 /// 类ChangedPropertyReflector中用到。 /// </summary> public string Description { get { return _description; } set { _description = value; } } private string _description = ""; /// <summary> /// 集合中元素的临时顺序号属性名,用CodeRobot代码生成器生成的业务实体才有这个属性. /// 但是不是用用CodeRobot代码生成器生成的业务实体也可以使用这个集合。 /// </summary> public string SequenceNoPropertyName { get { return _sequenceNoPropertyName; } } private string _sequenceNoPropertyName = "TmpSequenceNo"; public int TmpSequenceNo { get { return _tmpSequenceNo; } protected set { _tmpSequenceNo = value; } } private int _tmpSequenceNo = 0; private string _propertyName; private bool _isAscending; //是否升序排序 /// <summary> /// 排序时使用的一个临时类 /// </summary> private class SortPosition { public string propValue; //某个属性值 public int start; //某个属性值开始位置 public int end; //某个属性值结束位置 public int count; //某个属性值出现的个数 } private ArrayList sortArray; //排序时使用的一个临时数组,成员SortPosition //构造函数 public GenericList() { innerList = new List<T>(); } #region SortBy /// <summary> /// 把集合成员按照两个属性(字段)的值排序,属性名区分大小写 /// </summary> /// <param name="propertyName">属性名称,区分大小写</param> /// <param name="ascending">true表示按升序排序</param> public void SortBy(string propertyName, bool ascending) { if (propertyName == "") { return; } if (_propertyName == propertyName && _isAscending == ascending) _isAscending = !ascending; else { _propertyName = propertyName; _isAscending = ascending; } PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(typeof(T)); PropertyDescriptor propertyDesc = properties.Find(propertyName, true); if (propertyDesc == null) { throw new Exception("SortBy: Not found property:" + propertyName); } // 应用排序 PropertyComparer<T> pc; pc = new PropertyComparer<T>(propertyDesc, (_isAscending) ? ListSortDirection.Ascending : ListSortDirection.Descending); innerList.Sort(pc); } /// <summary> /// 把集合成员按照两个属性(字段)的值排序,属性名区分大小写 /// </summary> /// <param name="propertyName1"></param> /// <param name="propertyName2"></param> /// <param name="ascending1">true表示按升序排序</param> ///<param name="ascending2">true表示按升序排序</param> public void SortBy(string propertyName1, bool ascending1, string propertyName2, bool ascending2) { if (propertyName1 == "") { return; } PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(typeof(T)); PropertyDescriptor propertyDesc = properties.Find(propertyName1, true); if (propertyDesc == null) { throw new Exception("SortBy: Not found property:" + propertyName1); } // 应用排序 PropertyComparer<T> pc; pc = new PropertyComparer<T>(propertyDesc, (ascending1) ? ListSortDirection.Ascending : ListSortDirection.Descending); innerList.Sort(pc); //第一轮按照第一个属性排序 //开始第二个属性排序的计算 int index = 0; string propVal = "", prevPropVal = ""; //前一个不同的属性值 SortPosition sp; sortArray = new ArrayList(); foreach (T obj in innerList) { propVal = (PropertyComparer<T>.GetPropertyValue(obj, propertyName1)).ToString(); if (index == 0) { sp = new SortPosition(); sp.propValue = propVal; sp.start = index; sortArray.Add(sp); prevPropVal = propVal; } else { if (propVal != prevPropVal) { //如果有新值出现,则计算前一各值的数量,并将新值所代表的位置加入到sortArray里去. ((SortPosition)sortArray[sortArray.Count - 1]).end = index; ((SortPosition)sortArray[sortArray.Count - 1]).count = index - ((SortPosition)sortArray[sortArray.Count - 1]).start; sp = new SortPosition(); sp.propValue = propVal; sp.start = index; sortArray.Add(sp); prevPropVal = propVal; } } if (index == innerList.Count - 1) { //最后一个 ((SortPosition)sortArray[index - 1]).end = index; //最后一个值的数量. sortArray.Count - 2 :sortArray的倒数第二个元素 if (propVal != prevPropVal) { ((SortPosition)sortArray[sortArray.Count - 1]).count = index - ((SortPosition)sortArray[sortArray.Count - 2]).end; } else { ((SortPosition)sortArray[sortArray.Count - 1]).count = index - ((SortPosition)sortArray[sortArray.Count - 2]).end + 1; } } index += 1; } //第二轮根据第一各属性的每一个不同值,按第二个属性排序 if (propertyName2 == "") { return; } else { foreach (SortPosition pos in sortArray) { propertyDesc = properties.Find(propertyName2, true); pc = new PropertyComparer<T>(propertyDesc, (ascending2) ? ListSortDirection.Ascending : ListSortDirection.Descending); innerList.Sort(pos.start, pos.count, pc); } } } #endregion #region FindBy /// <summary> /// 按某个属性(字段)的值在集合中查找对象,找到则返回满足条件的第一个对象,找不到返回对象的默认值。 /// 属性名是区分大小写的, 对象值转换成字符串比较。 /// </summary> /// <param name="propertyName"></param> /// <param name="propertyValue"></param> /// <param name="IgnoreCase">属性值是否忽略大小写</param> /// <returns></returns> public T FindBy(string propertyName, object propertyValue, bool ignoreCase) { T foundObj = default(T); string stringValue; string tmpVal; stringValue = propertyValue.ToString(); foreach (T obj in innerList) { tmpVal = PropertyComparer<T>.GetPropertyValue(obj, propertyName).ToString(); if (String.Compare(tmpVal, stringValue, ignoreCase) == 0) { foundObj = obj; break; } } return foundObj; } /// </summary> /// 按两个属性(字段)的值在集合中查找对象,找到则返回满足条件的第一个对象,找不到返回对象的默认值。 /// 属性名是区分大小写的, 对象值转换成字符串比较。 /// </summary> /// <param name="propertyName1"></param> /// <param name="propertyValue1"></param> /// <param name="propertyName2"></param> /// <param name="propertyValue2"></param> /// <param name="ignoreCase">屬性值是否忽略大小写</param> /// <returns></returns> public T FindBy(string propertyName1, object propertyValue1, string propertyName2, object propertyValue2, bool ignoreCase) { T foundObj = default(T); string stringValue1, stringValue2; stringValue1 = propertyValue1.ToString(); stringValue2 = propertyValue2.ToString(); foreach (T obj in innerList) { if (String.Compare(PropertyComparer<T>.GetPropertyValue(obj, propertyName1).ToString(), stringValue1, ignoreCase) == 0 && String.Compare(PropertyComparer<T>.GetPropertyValue(obj, propertyName2).ToString(), stringValue2, ignoreCase) == 0) { foundObj = obj; break; } } return foundObj; } /// </summary> /// 按三个属性(字段)的值在集合中查找对象,找到则返回满足条件的第一个对象,找不到返回对象的默认值。 /// 属性名是区分大小写的, 对象值转换成字符串比较。 /// </summary> public T FindBy(string propertyName1, object propertyValue1, string propertyName2, object propertyValue2, string propertyName3, object propertyValue3, bool ignoreCase) { T foundObj = default(T); string stringValue1, stringValue2, stringValue3; stringValue1 = propertyValue1.ToString(); stringValue2 = propertyValue2.ToString(); stringValue3 = propertyValue3.ToString(); foreach (T obj in innerList) { if (String.Compare(PropertyComparer<T>.GetPropertyValue(obj, propertyName1).ToString(), stringValue1, ignoreCase) == 0 && String.Compare(PropertyComparer<T>.GetPropertyValue(obj, propertyName2).ToString(), stringValue2, ignoreCase) == 0 && String.Compare(PropertyComparer<T>.GetPropertyValue(obj, propertyName3).ToString(), stringValue3, ignoreCase) == 0) { foundObj = obj; break; } } return foundObj; } #endregion /// <summary> /// 返回某个属性等于某个值的子集合。 /// 属性名是区分大小写的, 对象值转换成字符串比较。 /// </summary> /// <param name="propertyName"></param> /// <param name="propertyValue"></param> /// <param name="byReference">是否生成一个新的子集合,如果是true, 則子集合里的元素不再是大集合里的元素,而是一个新生成的对象</param> /// <param name="ignoreCase">属性值是否忽略大小写</param> /// <returns></returns> public GenericList<T> GetSubList(string propertyName, object propertyValue, bool ignoreCase) { GenericList<T> subColletion = new GenericList<T>(); string stringValue; stringValue = propertyValue.ToString(); //轉爲小寫比較 foreach (T obj in innerList) { if (String.Compare(PropertyComparer<T>.GetPropertyValue(obj, propertyName).ToString(), stringValue, ignoreCase) == 0) { subColletion.Add(obj); } } return subColletion; } /// <summary> /// 添加元素,并给集合成员的临时顺序号属性赋值. /// </summary> public void Add(T obj) { //对于用代码生成器生成的对象,才有这个属性:_sequenceNoPropertyName PropertyInfo pi = obj.GetType().GetProperty(SequenceNoPropertyName); if (pi != null) { //有该属性則赋值再添加,否则直接添加. pi.SetValue(obj, TmpSequenceNo, null); TmpSequenceNo += 1; } innerList.Add(obj); } /// <summary> /// 添加元素,并给集合成员的临时顺序号属性赋值. /// </summary> public void AddRange(IEnumerable<T> collection) { foreach (T obj in collection) { PropertyInfo pi = obj.GetType().GetProperty(SequenceNoPropertyName); if (pi != null) { pi.SetValue(obj, TmpSequenceNo, null); TmpSequenceNo += 1; } innerList.Add(obj); } } /// <summary> /// 添加元素,并给集合成员的临时顺序号属性赋值. /// </summary> public void AddRange(T[] objectArray) { foreach (T obj in objectArray) { PropertyInfo pi = obj.GetType().GetProperty(SequenceNoPropertyName); if (pi != null) { pi.SetValue(obj, TmpSequenceNo, null); TmpSequenceNo += 1; } innerList.Add(obj); } } public void Insert(int index, T obj) { PropertyInfo pi = obj.GetType().GetProperty(SequenceNoPropertyName); if (pi != null) { pi.SetValue(obj, TmpSequenceNo, null); TmpSequenceNo += 1; } innerList.Insert(index, obj); } public void InsertRange(int index, IEnumerable<T> collection) { int localIndex = index; foreach (T obj in collection) { PropertyInfo pi = obj.GetType().GetProperty(SequenceNoPropertyName); if (pi != null) { pi.SetValue(obj, TmpSequenceNo, null); TmpSequenceNo += 1; } innerList.Insert(localIndex, obj); localIndex += 1; } } #region 下面实现集合一些常用的属性和方法,一些不常用的方法没有实现,需要时可以自己添加。 public int Capacity { get { return innerList.Capacity; } set { innerList.Capacity = value; } } public int Count { get { return innerList.Count; } } /// <summary>索引器</summary> public T this[int index] { get { return ((T)(innerList[index])); } } public void Clear() { innerList.Clear(); } public bool Contains(T obj) { return innerList.Contains(obj); } public int IndexOf(T obj) { return innerList.IndexOf(obj); } public int LastIndexOf(T obj) { return innerList.LastIndexOf(obj); } public void CopyTo(T[] array) { innerList.CopyTo(array); } public void CopyTo(T[] array, int arrayIndex) { innerList.CopyTo(array, arrayIndex); } public void CopyTo(int index, T[] array, int arrayIndex, int count) { innerList.CopyTo(index, array, arrayIndex, count); } /// <summary> /// 拷贝到对象数组 /// </summary> /// <returns></returns> public T[] CopyToArray() { T[] objArray = new T[innerList.Count]; innerList.CopyTo(objArray); return objArray; } public bool Remove(T obj) { return innerList.Remove(obj); } public void RemoveAt(int index) { innerList.RemoveAt(index); } /// <summary>List的Find方法</summary> public T Find(Predicate<T> match) { return innerList.Find(match); } public List<T> FindAll(Predicate<T> match) { return innerList.FindAll(match); } public void Sort() { innerList.Sort(); } public void Sort(IComparer<T> comparer) { innerList.Sort(comparer); } #endregion #region 实现IEnumerable<T>的成员,绑定GridView所必须 public IEnumerator<T> GetEnumerator() { int count = innerList.Count; for (int i = 0; i < count; i++) { yield return innerList[i]; } } //实现IEnumerable(非泛型)的成员,因为IEnumerable<T>继承自非泛型IEnumerable. IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } #endregion } }
2.定义的实体类Travel.cs
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace CustomListTest { public class Travel { public Travel(string flight,DateTime flyTime,double price,int seatCount) { Flight = flight; FlyTime = flyTime; Price = price; SeatCount = seatCount; } /// <summary> /// 航班 /// </summary> public string Flight { get; set; } /// <summary> /// 起飞时间 /// </summary> public DateTime FlyTime { get; set; } /// <summary> /// 价格 /// </summary> public double Price { get; set; } /// <summary> /// 座位剩余量 /// </summary> public int SeatCount { get; set; } } }
3.自定义的一个属性比较的类PropertyComparer.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;
using System.Reflection;
namespace CustomListTest
{
/// <summary>
/// 属性比较类
/// </summary>
public class PropertyComparer<T> : System.Collections.Generic.IComparer<T>
{
private PropertyDescriptor _property;
private ListSortDirection _direction;
public PropertyComparer(PropertyDescriptor property, ListSortDirection direction)
{
_property = property;
_direction = direction;
}
#region IComparer<T>
public int Compare(T xWord, T yWord)
{
// 获取属性
object xValue = GetPropertyValue(xWord, _property.Name);
object yValue = GetPropertyValue(yWord, _property.Name);
// 调用升序或降序方法
if (_direction == ListSortDirection.Ascending)
{
return CompareAscending(xValue, yValue);
}
else
{
return CompareDescending(xValue, yValue);
}
}
public bool Equals(T xWord, T yWord)
{
return xWord.Equals(yWord);
}
public int GetHashCode(T obj)
{
return obj.GetHashCode();
}
#endregion
/// <summary>
/// 比较任意类型属性升序
/// </summary>
/// <param name="xValue">X值</param>
/// <param name="yValue">Y值</param>
/// <returns></returns>
private int CompareAscending(object xValue, object yValue)
{
int result;
// 如果值实现了IComparer接口
if (xValue is IComparable)
{
result = ((IComparable)xValue).CompareTo(yValue);
}
// 如果值没有实现IComparer接口,但是它们是相等的
else if (xValue.Equals(yValue))
{
result = 0;
}
// 值没有实现IComparer接口且它们是不相等的, 按照字符串进行比较
else result = xValue.ToString().CompareTo(yValue.ToString());
return result;
}
/// <summary>
/// 比较任意类型属性降序
/// </summary>
/// <param name="xValue">X值</param>
/// <param name="yValue">Y值</param>
/// <returns></returns>
private int CompareDescending(object xValue, object yValue)
{
return CompareAscending(xValue, yValue) * -1;
}
/// <summary>
/// 获取属性值
/// </summary>
/// <param name="value">对象</param>
/// <param name="property">属性</param>
/// <returns></returns>
public static object GetPropertyValue(T value, string property)
{
// 获取属性
PropertyInfo propertyInfo = value.GetType().GetProperty(property);
// 返回值
return propertyInfo.GetValue(value, null);
}
}
}
4.后台调用的简单方法Program.cs,这里只演示了按照属性一的升序和属性二的降序排列
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace CustomListTest { class Program { static void Main(string[] args) { Travel travel1 = new Travel("1001",DateTime.Now.AddDays(1),151,24); Travel travel2 = new Travel("1002", DateTime.Now.AddDays(4), 152, 45); Travel travel3 = new Travel("1003", DateTime.Now.AddDays(3), 153, 12); Travel travel4 = new Travel("1004", DateTime.Now.AddDays(7), 154, 5); Travel travel5 = new Travel("1005", DateTime.Now.AddDays(5), 155, 32); Travel travel6= new Travel("1006", DateTime.Now.AddDays(4), 156, 32); Travel travel7 = new Travel("1007", DateTime.Now.AddDays(5), 151, 32); Travel travel8 = new Travel("1008", DateTime.Now.AddDays(4), 156, 32); Travel travel9= new Travel("1009", DateTime.Now.AddDays(7), 151, 32); Travel travel10 = new Travel("1010", DateTime.Now.AddDays(7), 152, 32); TravelList<Travel> list = new TravelList<Travel>(); list.Add(travel1); list.Add(travel2); list.Add(travel3); list.Add(travel4); list.Add(travel5); list.Add(travel6); list.Add(travel7); list.Add(travel8); list.Add(travel9); list.Add(travel10); list.Sort("FlyTime", true, "Price", false); foreach (var item in list) { Console.WriteLine(item.Flight + " " + item.FlyTime + " " + item.Price + " " + item.SeatCount); } Console.Read(); } } }