-2

I'm floundering with this. A friend wrote this sometime ago and is now in another state so cannot help with expanding the idea.

// For index listing.
// Order function to identify sort direction.
private IOrderedEnumerable<Client> OrderClients<T>(IEnumerable<Client> clients, Func<Client, T> keySelector, SortDirection sortDirection) {
    return sortDirection == SortDirection.desc
            ? clients.OrderByDescending(keySelector)
            : clients.OrderBy(keySelector);
}

It works.

However my requirements have changed.

I now want a static method that can be supplied with an IEnumerable<T> and a dictionary of <string, SortDirection> where SortDirection is the direction as an enum:

public enum SortDirection
{
    asc = 0,
    desc
}

This is because the Dictionary may have as many as 4 columns to sort by. The first value is always the orderBy and all the others are thenBy.

so I tried to start with the following method signature.

public static IOrderedEnumerable<T> OrderAndThenBy(IEnumerable<T> list, Func<T, Dictionary<string, SortDirection>>){}

I wanted to accept an IEnumerable and then use the dictionary with the columns to sort by "string" and the direction it should be sorted in.

This answer by Matthias seemed promising but at the heart of this I don't understand the mechanics of how the Func works as a parameter in order to use the dictionary of <key = columns, value = sortDirection> on the IEnumerable<T> (generic so I can use it on all tables that I require sorting) and then return an IOrderedEnumerable<T>..

Could someone help with the structure of the method and also how to use the Func as a method parameter with one parameter of type Dictionary. At the moment I am getting an error on the "T"..

Error CS0246 The type or namespace name 'T' could not be found (are you missing a using directive or an assembly reference?)

because I have not written the generic method parameters correctly.. Hope someone might be able to help.

marc_s
  • 675,133
  • 158
  • 1,253
  • 1,388
si2030
  • 2,799
  • 4
  • 25
  • 60
  • I am not sure i understood correctly but depending on your table relation. You can use 2 orderby. Someting like this.. clients.OrderBy(keySelector1).OrderBy(keySelector2) – AliAzra Aug 25 '19 at 07:38
  • 1
    Why a `static` method? That does not follow from your requirements. – Henk Holterman Aug 25 '19 at 08:06
  • Given that you can do `var query2 = query1.SomeOrderMethod();` multiple times before returning, you could write this out yourself. – Henk Holterman Aug 25 '19 at 08:16
  • Hi Henk, I am getting a query statement that I break up filter and sort. the sort I wanted generic because I want it not just for the clients table but for the jobs table and so on.. yes I could write this several times again and again in each of these but its better isnt it to have reusable code ie to run a generic method shared between all services that require a sort. I also wanted to use the Func statement and I felt it should be a static method so I dont have to instantiate it... I also felt that there a number of people who also have trouble with Func and would like an example. – si2030 Aug 25 '19 at 08:41
  • So.. generic because the table being sorted can change and of course each table has different columns to sort by and as well they could be asc or desc and on top of that its orderby and thenby.. It could be one column or 4 - you dont know until you get the dictionary.. so its particularly flexible. – si2030 Aug 25 '19 at 08:43
  • What you need is an Expression Trees based solution, which finally converts into Func as required by chained OrderBy clause and in process method may be static is its an extension method for `IEnumerable`, otherwise not required – Mrinal Kamboj Aug 26 '19 at 07:19
  • Mostly your Q. is incorrectly framed requirements and unable to understand the working of simple things like Func, which is the simple input for the OrderBy clause, your requirement of static has more to do with Extension methods for Linq chaining then just plain vanilla static. No amount of explanation will help but review these links, [Dynamic Order By Linq](https://stackoverflow.com/questions/41244/dynamic-linq-orderby-on-ienumerablet-iqueryablet/233505#233505) and [Dynamic SQL-like Linq OrderBy Extension](http://aonnull.blogspot.com/2010/08/dynamic-sql-like-linq-orderby-extension.html) – Mrinal Kamboj Aug 27 '19 at 09:39
  • Above two links posted by me solve the exact problem set, only thing is you have to modify your input to align with the API inputs – Mrinal Kamboj Aug 27 '19 at 09:40

1 Answers1

0

You get the error because you need to include the generic type T in the method declaration after the name (see [1]), like that:

public static IOrderedEnumerable<T> OrderAndThenBy<T>(IEnumerable<T> list, Func<T, Dictionary<string, SortDirection>> sortInfo){}

It is much more difficult to provide the info which property to sort by (key) to the OrderBy method as string like you are trying, so you better keep the key selection like in the initial OrderClients method. There, the keySelector is a delegate [3, 2] which takes a Client, and returns a property of the Client, so that the OrderBy methods know which property you want to sort by. Now that you have multiple properties, which all could have different types, it is not sufficient to provide one type parameter anymore. But as you also do not know the number of properties that you want to sort, you cannot define all type parameters statically. As not the cleanest but simple workaround you could drop the type, and change the delegate to return object instead T.

You probably still work just with Clients, so you should keep the return type from the original method.

Note that the order of elements in a dictionary is undefined [4], but order is important in this case, so you should replace it with e.g. a list [5].

Taken all together, you might come up with a method like:

public static IOrderedEnumerable<Client> OrderAndThenBy(IEnumerable<Client> list,  List<KeyValuePair<Func<Broker, object>, SortDirection>> sortInfo) {}

[1] https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/generics/generic-methods

[2] https://docs.microsoft.com/en-us/dotnet/api/system.func-2?view=netframework-4.8

[3] https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/delegates/

[4] https://docs.microsoft.com/en-us/dotnet/api/system.collections.generic.dictionary-2

[5] https://docs.microsoft.com/en-us/dotnet/standard/collections/selecting-a-collection-class

demo
  • 5,376
  • 12
  • 55
  • 130
user7217806
  • 1,714
  • 2
  • 7
  • 10