23

There are two formats for any given Linq expression with a custom sort comparer:

Format 1

var query =
    source
    .Select(x => new { x.someProperty, x.otherProperty } )
    .OrderBy(x => x, new myComparer());

Format 2

var query =
    from x in source
    orderby x // comparer expression goes here?
    select new { x.someProperty, x.otherProperty };

Question:
What is the syntax for the order-by expression in the second format?

Not the question:
How to use a custom comparer as shown in the first format.

Bonus credit:
Are there actual, formal names for the two Linq formats listed above?

Steve Konves
  • 2,648
  • 3
  • 25
  • 44

4 Answers4

24

What is the syntax for the order-by expression in the second format?

It doesn't exist. From the orderby clause documentation:

You can also specify a custom comparer. However, it is only available by using method-based syntax.


How to use a custom comparer in the first format.

You wrote it correctly. You can pass the IComparer<T> as you wrote.


Are there actual, formal names for the two Linq formats listed above?

Format 1 is called "Method-Based Syntax" (from previous link), and Format 2 is "Query Expression Syntax" (from here).

Reed Copsey
  • 554,122
  • 78
  • 1,158
  • 1,373
3

This isn't necessarily answering the original question, but it somewhat extends some of the possibilities outlined. I am posting this in case others come across the similar problem. The solution posted here outlines a generic order by option that may be useful in other cases. In this example, I wanted to sort a file list by different properties.

/// <summary>
/// Used to create custom comparers on the fly
/// </summary>
/// <typeparam name="T"></typeparam>
public class GenericCompare<T> : IComparer<T>
{
    // Function use to perform the compare
    private Func<T, T, int> ComparerFunction { set; get; }

    // Constructor
    public GenericCompare(Func<T, T, int> comparerFunction)
    {
        ComparerFunction = comparerFunction;
    }

    // Execute the compare
    public int Compare(T x, T y)
    {

        if (x == null || y == null) 
        {
            // These 3 are bell and whistles to handle cases where one of the two is null, to sort to top or bottom respectivly
            if (y == null && x == null) { return 0; }
            if (y == null) { return 1; }
            if (x == null) { return -1; }
        }

        try
        {
            // Do the actual compare
            return ComparerFunction(x, y);
        }
        catch (Exception ex)
        {
            // But muffle any errors
            System.Diagnostics.Debug.WriteLine(ex);
        }

        // Oh crud, we shouldn't be here, but just in case we got an exception.
        return 0;
    }
}

Then in the implementation…

        GenericCompare<FileInfo> DefaultComparer;

        if (SortOrder == SORT_FOLDER_FILE)
        {
            DefaultComparer = new GenericCompare<FileInfo>((fr1, fr2) =>
            {
                return fr1.FullName.ToLower().CompareTo(fr2.FullName.ToLower());
            });
        }
        else if (SortOrder == SORT_SIZE_ASC)
        {
            DefaultComparer = new GenericCompare<FileInfo>((fr1, fr2) =>
            {
                return fr1.Length.CompareTo(fr2.Length);
            });
        }
        else if (SortOrder == SORT_SIZE_DESC)
        {
            DefaultComparer = new GenericCompare<FileInfo>((fr1, fr2) =>
            {
                return fr2.Length.CompareTo(fr1.Length);
            });
        }
        else
        {
            DefaultComparer = new GenericCompare<FileInfo>((fr1, fr2) =>
            {
                return fr1.Name.ToLower().CompareTo(fr2.Name.ToLower());
            });
        }

        var ordered_results = (new DirectoryInfo(@"C:\Temp"))
                .GetFiles()
                .OrderBy(fi => fi, DefaultComparer);

The big advantage is that you then don’t need to create a new class for each order by case, you can just wire up a new lambda. Obviously this can be extended in all sorts of ways, so hopefully it will helps someone, somewhere, sometime.

Brad Joss
  • 31
  • 1
2

How to use a custom comparer as shown in the first format.

You can't use a custom comparer in that format.

Are there actual, formal names for the two Linq formats listed above?

Format 1 is Method syntax, Format 2 is "query syntax",

Servy
  • 202,030
  • 26
  • 332
  • 449
1

Question:

Thats not possible in the query syntax, because there are no overloads.

Not the question:

You can use a comparer with anonymous types only if you use reflection to compare the objects, it's better to use a typed implementation for comparing.

If you don't want to create a typed implementation you can use a Tuple:

var query =
    source
    .Select(x => new Tuple<string, int>(x.someProperty, x.otherProperty))
    .OrderBy(x => x, new MyComparer());

public class MyComparer : IComparer<Tuple<string, int>>
{
  public int Compare(Tuple<string, int> x, Tuple<string, int> y)
  {
    return x.Item1.CompareTo(y.Item1);
  }
}

Bonus credit:

  • Query syntax or Comprehension Syntax
  • Method syntax or Extension method Syntax
Erwin
  • 4,757
  • 3
  • 31
  • 41