Подтвердить что ты не робот

Linq для OrderBy с пользовательским Comparer <T>

Существует два формата для любого выражения Linq с пользовательским сортировщиком сортировки:

Формат 1

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

Формат 2

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

Вопрос:
Каков синтаксис выражения order-by во втором формате?

Не вопрос:
Как использовать пользовательский сопоставитель, как показано в первом формате.

Бонусный кредит:
Существуют ли реальные формальные имена для двух форматов Linq, перечисленных выше?

4b9b3361

Ответ 1

Каков синтаксис выражения order-by во втором формате?

Он не существует. Из документации заказа orderby:

Вы также можете указать пользовательский сопоставитель. Однако он доступен только с использованием синтаксиса на основе метода.


Как использовать пользовательский сопоставитель в первом формате.

Вы написали это правильно. Вы можете передать IComparer<T>, как вы писали.


Существуют ли реальные, формальные имена для двух форматов Linq, перечисленных выше?

Формат 1 называется "Синтаксис на основе метода" (из предыдущей ссылки), а Format 2 - "Синтаксис выражения запроса" (от здесь).

Ответ 2

Как использовать пользовательский сопоставитель, как показано в первом формате.

Вы не можете использовать пользовательский сопоставитель в этом формате.

Существуют ли реальные, формальные имена для двух форматов Linq, перечисленных выше?

Формат 1 - синтаксис метода, формат 2 - это синтаксис запроса,

Ответ 3

Вопрос:

Это невозможно в синтаксисе запроса, поскольку перегрузки отсутствуют.

Не вопрос:

Вы можете использовать сопоставление с анонимными типами, только если вы используете отражение для сравнения объектов, лучше использовать типизированную реализацию для сравнения.

Если вы не хотите создавать типизированную реализацию, вы можете использовать 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);
  }
}

Бонусный кредит:

  • Синтаксис запроса или Синтаксис понимания.
  • Синтаксис метода или метод расширения Синтаксис

Ответ 4

Это не обязательно отвечает на исходный вопрос, но несколько расширяет некоторые из изложенных возможностей. Я отправляю это, если другие сталкиваются с подобной проблемой. Решение, размещенное здесь, описывает общий порядок по выбору, который может быть полезен в других случаях. В этом примере я хотел отсортировать список файлов по различным свойствам.

/// <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;
    }
}

Затем в реализации...

        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);

Большим преимуществом является то, что вам тогда не нужно создавать новый класс для каждого заказа в каждом случае, вы можете просто подключить новую лямбду. Очевидно, это может быть расширено разными способами, поэтому, надеюсь, это когда-нибудь поможет кому-то.