简体   繁体   中英

System.Linq.Expressions.Expression for .OrderBy function

I have a line section of my code that is repetitive.

You will see the lambda expression below repeat 4 times

x => x.GetValue<string>("City")).ThenByDescending(x => HelperFunctions.strToTZDateTime(x.GetValue<string>("EventStartStr"), x.GetValue<string[]>("EventTimeZone")[0].ToString())

The code example :

//SORT DATA
    switch (SortDetails)
    {
        case ("Date"):
        default:
            if (SortOrder == "ASC")
            {
                _allEvents = _allEvents.OrderBy(x => HelperFunctions.strToTZDateTime(x.GetValue<string>("EventStartStr"), x.GetValue<string[]>("EventTimeZone")[0].ToString()));
            }
            else
            {
                _allEvents = _allEvents.OrderByDescending(x => HelperFunctions.strToTZDateTime(x.GetValue<string>("EventStartStr"), x.GetValue<string[]>("EventTimeZone")[0].ToString()));
            }
            break;
        case ("Location"):
            if (SortOrder == "ASC")
            {
                _allEvents = _allEvents.OrderBy(x => x.GetValue<string>("Country")).ThenBy(x => x.GetValue<string>("ProvinceState")).ThenBy(x => x.GetValue<string>("City")).ThenBy(x => HelperFunctions.strToTZDateTime(x.GetValue<string>("EventStartStr"), x.GetValue<string[]>("EventTimeZone")[0].ToString()));
            }
            else
            {
                _allEvents = _allEvents.OrderByDescending(x => x.GetValue<string>("Country")).ThenByDescending(x => x.GetValue<string>("ProvinceState")).ThenByDescending(x => x.GetValue<string>("City")).ThenByDescending(x => HelperFunctions.strToTZDateTime(x.GetValue<string>("EventStartStr"), x.GetValue<string[]>("EventTimeZone")[0].ToString()));
            }
            break;
    }

I would like to take the first line and make it into something I can just plop into the OrderBy's.

Something like :

System.Linq.Expressions.Expression<Func<DynamicContent, DateTime>> sortLambda = x => HelperFunctions.strToTZDateTime(x.GetValue<string>("EventStartStr"), x.GetValue<string[]>("EventTimeZone")[0].ToString());

into :

allEvents = _allEvents.OrderBy(sortLambda);

Unfortunately that didn't seem to work well.

This console app should fix you up. The sortLamda can be of any type, which hopefully answers your question about Dynamic Content.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Linq.Expressions;

internal class BoringEvent
{
    public string EventStartStr { get; set; }
    public string EventTimeZone { get; set; }
    public string ProvinceState { get; set; }
    public string City { get; set; }
    public string Country { get; set; }
}

internal enum SortedBy
{
    Ascending = 0,
    Descending
}

class ExpressionsTest
{
    internal static List<BoringEvent> _allEvents = new List<BoringEvent>();
    internal static class HelperFunctions
    {
        public static DateTime strToTZDateTime(string startDate, 
            string timeZone)
        {
            //I'm too lazy to figure out dates by time zone.
            //Your function already has the logic, so why bother.
            //Let's assume the time zone is equal in this test case
            return DateTime.Parse(startDate);
        }
    }

    internal static void Main()
    {

        _allEvents.Add(new BoringEvent {
            EventStartStr = "12/31/1999", 
            //let's party like it's 1999 - (yawn) I'm stuck at this event :< 
            EventTimeZone = "en-us", 
            City = "Philadelphia", 
            ProvinceState = "Pennsylvania",
            Country = "United States of America"});
        _allEvents.Add(new BoringEvent
        {
            EventStartStr = "01/01/1970",
            EventTimeZone = "en-us",
            City = "New York",
            ProvinceState = "New York",
            Country = "United States of America"
        });
        IEnumerable<BoringEvent> sortedEvents = null;
        //sort by date
        Console.WriteLine("Sorting Events by Ascending date...");
        Expression<Func<BoringEvent, DateTime>> sortLamba = evt => HelperFunctions.strToTZDateTime(evt.EventStartStr, evt.EventTimeZone);
        sortedEvents = _allEvents.SortEvents(SortedBy.Ascending, sortLamba);
        Print(sortedEvents);
        //sort by country, then state, then city, then date
        Console.WriteLine("Sorting Events Desc by Country, then ProvinceState, then City, then Date");
        Expression<Func<BoringEvent, object>>[] sortLamba2 = new Expression<Func<BoringEvent, object>>[] 
        {
            evt => evt.Country,
            evt => evt.ProvinceState,
            evt => evt.City,
            evt => HelperFunctions.strToTZDateTime(evt.EventStartStr, evt.EventTimeZone)
        };
        sortedEvents = _allEvents.SortEvents(SortedBy.Descending, sortLamba2);   
        Print(sortedEvents);

        Console.Read();
    }

    private static void Print(IEnumerable<BoringEvent> events)
    {
        for(int i = 0; i < events.Count(); i++)
        {
            BoringEvent evt = events.ElementAt(i);
            Console.WriteLine("Event: {0}", i.ToString());
            Console.WriteLine("\tEventStartStr: {0}", evt.EventStartStr);
            Console.WriteLine("\tEventTimeZone: {0}", evt.EventTimeZone);
            Console.WriteLine("\tCity: {0}", evt.City);
            Console.WriteLine("\tProvinceState: {0}", evt.ProvinceState);
            Console.WriteLine("\tCountry: {0}", evt.Country);
        }
    }
}

internal static class EventExtensions
{

    public static IEnumerable<TResult> SortEvents<TResult, T>(
        this IEnumerable<TResult> events, 
        SortedBy sortByType,
        params Expression<Func<TResult, T>>[] expressions)
    {
        IEnumerable<TResult> retVal = null;
        switch(sortByType)
        {
            case SortedBy.Ascending:
                retVal = EventExtensions.SortEventsAsc(events, expressions);
                break;
            case SortedBy.Descending:
                retVal = EventExtensions.SortEventsDesc(events, expressions);
                break;
            default:
                throw new InvalidOperationException(
                    string.Format("The SortedBy enumeration does not contain a case for the value of '{0}'.", 
                    Enum.GetName(typeof(SortedBy), sortByType)));
        }
        return retVal;
    }

    public static IEnumerable<TResult> SortEventsAsc<TResult, T>(
        this IEnumerable<TResult> events, 
        params Expression<Func<TResult, T>>[] expressions)
    {
        IOrderedEnumerable<TResult> sorted = null;
        for(int i = 0; i < expressions.Count(); i++)
        {
            Expression<Func<TResult, T>> exp = 
                (Expression<Func<TResult, T>>)expressions[i];
            Func<TResult, T> deleg = exp.Compile();
            if(i == 0)
            {
                sorted = events.OrderBy(evt => deleg.Invoke(evt));
            }
            else
            {
                sorted = sorted.ThenBy(evt => deleg.Invoke(evt));
            }
        }
        return sorted;
    }

    public static IEnumerable<TResult> SortEventsDesc<TResult, T>(
        this IEnumerable<TResult> events,
        params Expression<Func<TResult, T>>[] expressions)
    {
        IOrderedEnumerable<TResult> sorted = null;
        for (int i = 0; i < expressions.Count(); i++)
        {
            Expression<Func<TResult, T>> exp = 
                (Expression<Func<TResult, T>>)expressions[i];
            Func<TResult, T> deleg = exp.Compile();
            if (i == 0)
            {
                sorted = events.OrderByDescending(evt => deleg.Invoke(evt));
            }
            else
            {
                sorted = sorted.ThenByDescending(evt => deleg.Invoke(evt));
            }
        }
        return sorted;
    }
}

I believe that the OrderBy method takes a Func<T1,T2> parameter, so you could possibly do this...

var func = x => HelperFunctions.strToTZDateTime(x.GetValue<string>("EventStartStr"), x.GetValue<string[]>("EventTimeZone")[0].ToString());

then pass func into _allEvents = _allEvents.OrderBy(func);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM