Gary O. Stenstrom
Gary O. Stenstrom

Reputation: 2294

Runtime Sorting and Types with Linq

I have seen numerous articles which all seem to nibble around the issue I am having but none have provided an actual resolution to the problem. Which is to say they all get me to about 98% solution only to fail in some small detail.

I have an IEnumerable that is collected at run time. This IEnumerable could be of ANYTHING. I will not know until runtime. I need to sort it however based on a list of propertyNames and sort directions in a List of KeyValuePair objects provided as an argument.

public static void SortData(IEnumerable<dynamic> dataToSort,  List<KeyValuePair<string, string>> sortArgs)
{
}

I first get the Type of the IEnumerable. I have created a method for this. I won't get into this detail here. It's been tested and does return the proper Type.

public static void SortData(IEnumerable<dynamic> dataToSort, List<KeyValuePair<string, string>> sortArgs)
{
    Type dataType = TypeService.GetType(data);  
}

I then attempt to create an initial IOrderedEnumerable that I can apply the sortArgs sort to.

public static void SortData(IEnumerable<dynamic> dataToSort,  List<KeyValuePair<string, string>> sortArgs)
{
    Type dataType   = TypeService.GetType(dataToSort);  

    // Create IOrderedEnumerable
    //
    var query       = from dataItem in dataToSort
                      orderby // ?????  
                      select dataItem;

    // apply sortArgs to IOrderedEnumerable
    //
    for(int argIDX = 0; argIDX < sortArgs.Count; argIDX++)
    {
        var arg             = sortArgs[argIDX];
        var sortField       = arg.Key.Trim();
        var sortDirection   = arg.Value.Trim().ToUpper();

        if(argIDX == 0)
        {
            if(sortDirection == "DESC")
            {
                query = query.OrderByDescending(e => e.GetType().GetProperty(sortField).GetValue(e));
            }
            else
            {
                query = query.OrderBy(e => e.GetType().GetProperty(sortField).GetValue(e));
            }
        }
        else
        {
            if(sortDirection == "DESC")
            {
                query = query.ThenByDescending(e => e.GetType().GetProperty(sortField).GetValue(e));
            }
            else
            {
                query = query.ThenBy(e => e.GetType().GetProperty(sortField).GetValue(e));
            }
        }
    }

    // After applying the sort retreive the contents
    //
    dataToSort = query.ToList();                      
}

It seems by this point I have all the information I should need to sort the original dataToSort argument. But defining a property to initialize the IOrderedEnumerable is eluding me.

I have tried a number of different techniques I have read about ...

var query       = from dataItem in dataToSort
                  orderby ( X => 1)    //ERR: The type of one of the expressions in the OrderBy clause is incorrect. Type inference failed in the call to 'OrderBy'.
                  select dataItem;

I have tried to create a new Typed list (since I know the type) so that the expressions in the OrderBy clause could be inferred more accurately.

var typedDataToSort = new List<dataType>(); //ERR: dataType is a variable used like a type
foreach(var item in dataToSort)
{
    typedDataToSort.Add( item );
}

        

I have tried to get the PropertyInfo for a property to sort on..

PropertyInfo propInfo = dataType.GetProperty(dataValueField);
var query             = from dataItem in dataToSort
                        orderby (x => propInfo.GetValue(x, null)) //ERR: The type of one of the expressions in the OrderBy clause is incorrect. Type inference failed in the call to 'OrderBy'. Of couse this could not work since `dataType` is an INSTANCE of
                        select dataItem; 
                        
                        
                        

I have just run out of ideas.

Upvotes: 0

Views: 226

Answers (1)

Dominik
Dominik

Reputation: 1741

To create an IOrderedIEnumerable from a List<T> without manipulating the order you can just execute a noop sort by doing something like this:

var myList = new List<String>(){"test1", "test3", "test2"}
IOrderedIEnumerable<String> query = myList.OrderBy(x => 1);

The same goes for an IEnumerable - however you must ensure that the underlaying type of IEnumerable provides stable order for each iteration.

Upvotes: 1

Related Questions