GenericSorter
Code .NET SQL :: ASP.NET :: C#
Page 1 sur 1
GenericSorter
Utilisation
Classe
- Code:
protected void GridViewListeActualites_Sorting(object sender, GridViewSortEventArgs e)
{
Sorter<Actualite> sort = new Sorter<Actualite>(actualites, e.SortExpression + " " + sortDirection);
List<Actualite> sorted = sort.GetSortedList();
GridViewListeActualites.DataSource = sorted;
GridViewListeActualites.DataBind();
}
Classe
- Code:
using System;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
using System.Reflection.Emit;
namespace GenericSorter
{
#region Enums
/// <summary>
/// Enum that specifies the sort order
/// </summary>
public enum SortOrderEnum { ASC = 1, DESC = -1 };
/// <summary>
/// Enum that specifies the sort order type
/// Default = Compare using types default comparer
/// String = Compare ToString() values
/// </summary>
public enum SortOnEnum { Default = 0, String = 1 };
#endregion
#region Sorter class
/// <summary>
/// Sorter class
/// </summary>
/// <typeparam name="TObject">Generic type. Can be any object.</typeparam>
public class Sorter<TObject>
{
#region variables
private List<TObject> _OriginalList;
private List<ObjectSortProperty> _ObjectSortOnProperties;
#endregion
#region Constructors
/// <summary>
/// Sort collection of objects
/// </summary>
/// <param name="itemCollection">Object collection</param>
/// <param name="orderBy">SQL style Order by. Property names are CASE SENSITIVE. Properties are sorted with property datatype default comparer</param>
public Sorter(IEnumerable itemCollection, string orderBy)
: this(itemCollection, ParseOrderBy(orderBy))
{ }
/// <summary>
/// Sort collection of objects
/// </summary>
/// <param name="itemCollection">Object collection</param>
/// <param name="objectSortProperties">List of objects' sort properties to sort on</param>
public Sorter(IEnumerable itemCollection, IEnumerable<ObjectSortProperty> objectSortProperties)
{
_OriginalList = new List<TObject>();
_ObjectSortOnProperties = new List<ObjectSortProperty>();
SetNewCollection(itemCollection, objectSortProperties);
}
#endregion
#region Static private methods
private static List<ObjectSortProperty> ParseOrderBy(string orderBy)
{
if (orderBy == null || orderBy.Length == 0)
return new List<ObjectSortProperty>(0);
string[] props = orderBy.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
List<ObjectSortProperty> properties = new List<ObjectSortProperty>(props.Length);
for (int i = 0; i < props.Length; i++)
{
string prop = props[i].Trim();
string[] words = prop.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
if (words.Length > 2)
throw new ArgumentException("Too many words in sort expression", "orderBy");
if (words.Length == 2 && (!words[1].Equals("DESC", StringComparison.OrdinalIgnoreCase) && !words[1].Equals("ASC", StringComparison.OrdinalIgnoreCase)))
throw new ArgumentException("The second word in the sort expression must be ASC or DESC", "orderBy");
if (words.Length == 1 || words[1].Equals("ASC", StringComparison.OrdinalIgnoreCase))
properties.Add(new ObjectSortProperty(words[0], SortOrderEnum.ASC));
else
properties.Add(new ObjectSortProperty(words[0], SortOrderEnum.DESC));
}
return properties;
}
#endregion
#region Public methods
/// <summary>
/// Gets the sorted list of items
/// </summary>
/// <returns>Generic list of sorted objects</returns>
public List<TObject> GetSortedList()
{
return _OriginalList;
}
/// <summary>
/// Gets the sorted array of items
/// </summary>
/// <returns>Generic array of sorted objects</returns>
public TObject[] GetSortedArray()
{
return _OriginalList.ToArray();
}
/// <summary>
/// Set new collection to sort on already given properties
/// </summary>
/// <param name="newCollection">Object implemeting IEnumerable to sort</param>
public void SetNewCollection(IEnumerable newCollection)
{
AddObjectsToList(newCollection);
}
/// <summary>
/// Set new collection to sort on new properties
/// </summary>
/// <param name="newCollection">Object implemeting IEnumerable to sort</param>
/// <param name="objectSortProperty"></param>
public void SetNewCollection(IEnumerable newCollection, IEnumerable<ObjectSortProperty> objectSortProperties)
{
AddObjectSortPropertiesToList(objectSortProperties);
AddObjectsToList(newCollection);
}
public void SetNewSortProperties(IEnumerable<ObjectSortProperty> objectSortProperties)
{
AddObjectSortPropertiesToList(objectSortProperties);
SortList();
}
private void AddObjectsToList(IEnumerable newCollection)
{
_OriginalList.Clear();
foreach (TObject item in newCollection)
_OriginalList.Add(item);
SortList();
}
private void AddObjectSortPropertiesToList(IEnumerable<ObjectSortProperty> objectSortProperties)
{
_ObjectSortOnProperties.Clear();
foreach (ObjectSortProperty property in objectSortProperties)
_ObjectSortOnProperties.Add(property);
}
#endregion
#region Private Methods
private void SortList()
{
// if one it means we're sorting on one property
if (_ObjectSortOnProperties.Count == 1)
{
// sort based on the SortOn property
if (_ObjectSortOnProperties[0].SortOn == SortOnEnum.String)
_OriginalList.Sort(CompareSinglePropertyString);
else
_OriginalList.Sort(CompareSinglePropertyDefault);
}
// ... else do complex multi property sort
else
{
_OriginalList.Sort(CompareValuesMultiProperty);
}
}
#region Comparer stuff
/// <summary>
/// Compares the current objects properties with another object properties of the same type.
/// </summary>
/// <param name="o1">First value to compare</param>
/// <param name="o2">Second value to compare</param>
/// <returns>Returns the IComparable.CompareTo result</returns>
private int CompareSinglePropertyDefault(TObject o1, TObject o2)
{
PropertyValueDelegate<TObject> GetPropValue = GetPropertyValueDelegate<TObject>(_ObjectSortOnProperties[0].PropertyName);
object obj1 = GetPropValue(o1);
object obj2 = GetPropValue(o2);
// if sort order is decsending then reverse the result.
return _ObjectSortOnProperties[0].SortOrderMultiplier * ((IComparable)obj1).CompareTo(obj2);
}
private int CompareSinglePropertyString(TObject o1, TObject o2)
{
PropertyValueDelegate<TObject> GetPropValue = GetPropertyValueDelegate<TObject>(_ObjectSortOnProperties[0].PropertyName);
string obj1 = GetPropValue(o1).ToString();
string obj2 = GetPropValue(o2).ToString();
// if sort order is decsending then reverse the result.
return _ObjectSortOnProperties[0].SortOrderMultiplier * obj1.CompareTo(obj2);
}
private int CompareValuesMultiProperty(TObject o1, TObject o2)
{
int sortResult = 0;
List<ObjectSortProperty>.Enumerator enmr = _ObjectSortOnProperties.GetEnumerator();
while (sortResult == 0 && enmr.MoveNext())
{
PropertyValueDelegate<TObject> GetPropValue = GetPropertyValueDelegate<TObject>(enmr.Current.PropertyName);
object obj1 = GetPropValue(o1);
object obj2 = GetPropValue(o2);
// reflection Method - Old
/*object obj1 = typeof(TObject).GetProperty(enmr.Current.PropertyName).GetValue(o1, null);
object obj2 = typeof(TObject).GetProperty(enmr.Current.PropertyName).GetValue(o2, null);*/
if (enmr.Current.SortOn == SortOnEnum.String)
{
obj1 = obj1.ToString();
obj2 = obj2.ToString();
}
// if sort order is descending then reverse the result.
sortResult = enmr.Current.SortOrderMultiplier * ((IComparable)obj1).CompareTo(obj2);
}
enmr.Dispose();
return sortResult;
}
/// <summary>
/// Compares the current instance with another simple object of the same type.
/// </summary>
/// <param name="o1">First value to compare</param>
/// <param name="o2">Second value to compare</param>
/// <returns>Returns the IComparable.CompareTo result</returns>
private int CompareSimple(TObject o1, TObject o2)
{
return _ObjectSortOnProperties[0].SortOrderMultiplier * ((IComparable)o1).CompareTo(o2);
}
#endregion
#endregion
#region IL generator
public delegate object PropertyValueDelegate<TObj>(TObj obj);
public static PropertyValueDelegate<TObj> CreatePropertyValueDelegate<TObj>(string propertyName)
{
// Use Reflection to get the MethodInfo for our Property's get accessor
MethodInfo mi = typeof(TObj).GetMethod("get_" + propertyName);
if (mi == null)
throw new Exception("Property '" + propertyName + "' doesn't have a get implementation");
// Create a new Dynamic Method for retrieving the Property's value
DynamicMethod dm = new DynamicMethod("Get" + propertyName + "PropertyValue",
typeof(object), new Type[] { typeof(TObj) }, typeof(TObj).Module);
// Let's Emit some IL code to actually call the Property's accessor and return the value.
ILGenerator il = dm.GetILGenerator();
// Load arg 0 (Object) onto the stack
il.Emit(OpCodes.Ldarg_0);
// Call the property's get accessor (method) on the object that was loaded onto the stack
il.EmitCall(OpCodes.Call, mi, null);
// if the property's get accessor (method) returns a value(int, datetime, etc) type then we have to box it
if (mi.ReturnType.IsValueType)
il.Emit(OpCodes.Box, mi.ReturnType);
// Return the value (back to the caller) that was returned (to us) from calling the method above
il.Emit(OpCodes.Ret);
// Turn the Dynamic Method into a delegate and return it
return (PropertyValueDelegate<TObj>)dm.CreateDelegate(typeof(PropertyValueDelegate<TObj>));
}
private static Hashtable StoredDelegatesHashTable = new Hashtable();
public static PropertyValueDelegate<TObj> GetPropertyValueDelegate<TObj>(string propertyName)
{
object returnValue = StoredDelegatesHashTable[propertyName];
if (returnValue == null)
{
returnValue = CreatePropertyValueDelegate<TObj>(propertyName);
StoredDelegatesHashTable[propertyName] = returnValue;
}
return (PropertyValueDelegate<TObj>)returnValue;
}
#endregion
}
#endregion
#region ObjectSortProperty class
public class ObjectSortProperty
{
#region Variables
private string _PropertyName = string.Empty;
private SortOnEnum _SortOn = SortOnEnum.Default;
private int _SortOrder = Convert.ToInt16(SortOrderEnum.ASC);
#endregion
#region Constructor
public ObjectSortProperty(string propertyName)
: this(propertyName, SortOrderEnum.ASC)
{ }
public ObjectSortProperty(string propertyName, SortOrderEnum sortOrder)
: this(propertyName, sortOrder, SortOnEnum.Default)
{ }
/// <summary>
/// Constructor for property to sort an object on
/// </summary>
/// <param name="propertyName">Object's property to sort on</param>
/// <param name="sortOrder">Sort order</param>
/// <param name="sortOn">Sort on object's default comparer or on object.ToString()'s comparer</param>
public ObjectSortProperty(string propertyName, SortOrderEnum sortOrder, SortOnEnum sortOn)
{
_PropertyName = propertyName;
_SortOn = sortOn;
this.SortOrder = sortOrder;
}
#endregion
#region Properties
/// <summary>
/// Object's Property name to sort on
/// </summary>
public string PropertyName
{
get { return _PropertyName; }
set { _PropertyName = value; }
}
/// <summary>
/// Sort on object's default comparer or on object.ToString()'s comparer
/// </summary>
public SortOnEnum SortOn
{
get { return _SortOn; }
set { _SortOn = value; }
}
/// <summary>
/// Sort Order of sorted list
/// </summary>
public SortOrderEnum SortOrder
{
get
{
return (SortOrderEnum)_SortOrder;
}
set
{
_SortOrder = Convert.ToInt16(value);
}
}
/// <summary>
/// Get's the integer value of the sort order (1 = ASC, -1 = DESC). Used only for easier multiplication of comparer result so that no enum casting is needed
/// </summary>
public int SortOrderMultiplier
{
get { return _SortOrder; }
}
#endregion
}
#endregion
//class TestClass
//{
// private string _StringType = string.Empty;
// private int _IntType = 0;
// private decimal _DecimalType;
// public TestClass(string stringType, int intType, decimal decimalType)
// {
// this._StringType = stringType;
// this._IntType = intType;
// this._DecimalType = decimalType;
// }
// public string StringType
// {
// get { return _StringType; }
// set { _StringType = value; }
// }
// public int IntType
// {
// get { return _IntType; }
// set { _IntType = value; }
// }
// public decimal DecimalType
// {
// get { return _DecimalType; }
// set { _DecimalType = value; }
// }
//}
}
Code .NET SQL :: ASP.NET :: C#
Page 1 sur 1
Permission de ce forum:
Vous ne pouvez pas répondre aux sujets dans ce forum