Code .NET SQL
Vous souhaitez réagir à ce message ? Créez un compte en quelques clics ou connectez-vous pour continuer.
Le deal à ne pas rater :
Jeux, jouets et Lego : le deuxième à -50% (large sélection)
Voir le deal

GenericSorter

Aller en bas

GenericSorter Empty GenericSorter

Message  Admin Lun 5 Juil - 17:12

Utilisation

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; }
    //    }
    //}
}


Admin
Admin

Messages : 91
Date d'inscription : 20/09/2007

https://moaner101.forumpro.fr

Revenir en haut Aller en bas

Revenir en haut


 
Permission de ce forum:
Vous ne pouvez pas répondre aux sujets dans ce forum
Ne ratez plus aucun deal !
Abonnez-vous pour recevoir par notification une sélection des meilleurs deals chaque jour.
IgnorerAutoriser