extensions

Linq Extensions

Posted on Updated on

Here is my class of linq extensions I use.

This is an example of using the extension in a unit test.

[TestMethod]
public void Linq_OrderBy()
{
    List<User> userList = UserList.OrderBy( "FirstName"  ).ToList();
    Trace.WriteLine( "===  Order By FirstName ascending ===" );
    foreach ( User user in userList )
        Trace.WriteLine( $"FirstName: {user.FirstName},  LastName: {user.LastName}" );

    userList = UserList.OrderBy( "LastName", false ).ToList();
    Trace.WriteLine( "===  Order By LastName descending ====" );
    foreach ( User user in userList )
        Trace.WriteLine( $"FirstName: {user.FirstName},  LastName: {user.LastName}" );

}

private static readonly List<User> UserList = new List<User>() {
    new User { FirstName = "firstName03", LastName= "lastName08" },
    new User { FirstName = "firstName07", LastName= "lastName04" },
    new User { FirstName = "firstName06", LastName= "lastName05" },
    new User { FirstName = "firstName04", LastName= "lastName07" },
    new User { FirstName = "firstName10", LastName= "lastName01" },
    new User { FirstName = "firstName09", LastName= "lastName02" },
    new User { FirstName = "firstName08", LastName= "lastName03" },
    new User { FirstName = "firstName05", LastName= "lastName06" },
    new User { FirstName = "firstName02", LastName= "lastName09" },
    new User { FirstName = "firstName01", LastName= "lastName10" }
};
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;

namespace Dahl.Core.Extensions
{
    public static partial class Extensions
    {
        //-----------------------------------------------------------------------------------------
        /// <summary>
        /// Sorts the elements of a sequence according to a key. 
        /// </summary>
        /// <typeparam name="TSource"></typeparam>
        /// <typeparam name="TKey"></typeparam>
        /// <param name="source"></param>
        /// <param name="keySelector"></param>
        /// <param name="descending"></param>
        /// <returns></returns>
        public static IOrderedEnumerable<TSource> OrderBy<TSource, TKey>( this IEnumerable<TSource> source,
                                                                          Func<TSource, TKey> keySelector,
                                                                          bool descending )
        {
            if ( descending )
                return source.OrderByDescending( keySelector );

            return source.OrderBy( keySelector );
        }

        //-----------------------------------------------------------------------------------------
        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="TSource"></typeparam>
        /// <typeparam name="TKey"></typeparam>
        /// <param name="source"></param>
        /// <param name="keySelector"></param>
        /// <param name="descending"></param>
        /// <returns></returns>
        public static IOrderedQueryable<TSource> OrderBy<TSource, TKey>( this IQueryable<TSource> source,
                                                                         Expression<Func<TSource, TKey>> keySelector,
                                                                         bool descending )
        {
            return descending ? source.OrderByDescending( keySelector )
                              : source.OrderBy( keySelector );
        }

        //-----------------------------------------------------------------------------------------
        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="list"></param>
        /// <param name="sortExpression"></param>
        /// <param name="sortAscending"></param>
        /// <returns></returns>
        public static IQueryable<T> OrderBy<T>( this IQueryable<T> list, string sortExpression, bool sortAscending = true )
        {
            return sortAscending ? list.OrderBy( f => OrderFunc( f, sortExpression ) )
                                 : list.OrderByDescending( f => OrderFunc( f, sortExpression ) );
        }


        //-----------------------------------------------------------------------------------------
        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="list"></param>
        /// <param name="sortExpression"></param>
        /// <param name="sortAscending"></param>
        /// <returns></returns>
        public static IEnumerable<T> OrderBy<T>( this IEnumerable<T> list, string sortExpression, bool sortAscending = true )
        {
            return sortAscending ? list.OrderBy( f => OrderFunc( f, sortExpression ) )
                                 : list.OrderByDescending( f => OrderFunc( f, sortExpression ) );
        }

        //-----------------------------------------------------------------------------------------
        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="obj"></param>
        /// <param name="propertyName"></param>
        /// <returns></returns>
        public static object GetChildObject<T>( T obj, string propertyName )
        {
            Type t = obj.GetType();
            PropertyInfo prop = t.GetProperty( propertyName );
            if ( prop == null )
            {
                string msg = $"PropertyName \"{propertyName}\" is not defined in class \"{obj.GetType().FullName}\".";
                throw new ArgumentException( msg );
            }

            return prop.GetValue( obj, null ) ?? Activator.CreateInstance( prop.PropertyType );
        }

        //-----------------------------------------------------------------------------------------
        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="obj"></param>
        /// <param name="propertyName"></param>
        /// <returns></returns>
        private static object OrderFunc<T>( T obj, string propertyName )
        {
            string propName = propertyName;
            object newObj = obj;

            if ( propertyName.Contains( '.' ) )
            {   // the requested property is contained in a child object
                string[] parts = propertyName.Split( '.' );
                int numParts = parts.Length - 1;
                for ( int i = 0; i < numParts; i++ )
                    newObj = GetChildObject( newObj, parts[i] );

                propName = parts[numParts];
            }

            PropertyInfo propertyGetter = newObj.GetType()
                                                .GetProperty( propName, BindingFlags.Public | BindingFlags.Instance | BindingFlags.IgnoreCase );
            if ( propertyGetter == null )
            {
                string msg = @"Sort Expression could not find property name provided<br />" + $"PropertyName: {propertyName}";
                throw new ArgumentException( msg );
            }

            return propertyGetter.GetValue( newObj, null );
        }

        //-----------------------------------------------------------------------------------------
        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="TSrc"></typeparam>
        /// <typeparam name="TKey"></typeparam>
        /// <param name="src"></param>
        /// <param name="selector"></param>
        /// <returns></returns>
        public static IEnumerable<TSrc> DistinctBy<TSrc, TKey>( this IEnumerable<TSrc> src, Func<TSrc, TKey> selector )
        {
            HashSet<TKey> keys = new HashSet<TKey>();
            return src.Where( element => keys.Add( selector( element ) ) );
        }
    }
}