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

Можно ли использовать TryParse внутри Linq Comparable?

Вид:

Documenti = Documenti
    .OrderBy(o => string.IsNullOrEmpty(o.Note))
    .ThenBy(o => Int32.TryParse(o.Note))
    .ToList();

Это будет "игнорировать" (не порядок, если положить конец), если o.Note "" или нет int.

Как я могу это сделать?

4b9b3361

Ответ 1

Да, вы можете, если вы передадите правильные параметры int.TryParse. Обе перегрузки принимают int как out -параметр и инициализируют его внутри анализируемым значением. Так вот так:

int note;
Documenti = Documenti
    .OrderBy(o => string.IsNullOrEmpty(o.Note))
    .ThenBy(o => Int32.TryParse(o.Note, out note)) 
    .ToList();

Подход чистый использует метод, который анализирует на int и возвращает int?, если он не поддается анализу:

public static int? TryGetInt(this string item)
{
    int i;
    bool success = int.TryParse(item, out i);
    return success ? (int?)i : (int?)null;
}

Теперь вы можете использовать этот запрос (OrderByDescending, потому что true "больше", чем false):

Documenti = Documenti.OrderByDescending(d => d.Note.TryGetInt().HasValue).ToList();

Он более чистый, чем использование локальной переменной, которая используется в int.TryParse как параметр out.

Эрик Липперт прокомментировал мне другой ответ, где он приводит пример, когда это может повредить:

С# LINQ: как строка ( "[1, 2, 3]" ) анализируется как массив?

Ответ 2

int dummy;
Documenti = Documenti.OrderBy(
    o => Int32.TryParse(o.Note, out dummy) ?
        dummy :
        Int32.MaxValue /* or Int32.MinValue */
    ).ToList();

Примечание. Переключение между Int32.MaxValue и Int32.MinValue приведет либо к пустым значениям в начале, либо в конце списка.

Ответ 3

Это не приведет к ожидаемым результатам b/c TryParse возвращает a bool, а не int. Самое простое - создать функцию, которая возвращает int.

private int parseNote(string note) 
{   
  int num;   
  if (!Int32.TryParse(note, out num)) 
  {
    num = int.MaxValue; // or int.MinValue - however it should show up in sort   
  }

  return num; 
}

вызов этой функции из вашей сортировки

Documenti = Documenti
    .OrderBy(o => parseNote(o.Note))
    .ToList();

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

Ответ 4

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

List<Doc> Documenti = new List<Doc>() {
        new Doc(""),
        new Doc("1"),
        new Doc("-4"),
        new Doc(null) };

Documenti = Documenti.OrderBy(o => string.IsNullOrEmpty(o.Note)).ThenBy(o => 
{
    int result;
    if (Int32.TryParse(o.Note, out result))
    {
        return result;
    } else {
        return Int32.MaxValue;
    }
}).ToList();

foreach (var item in Documenti)
{
    Console.WriteLine(item.Note ?? "null");
    // Order returned: -4, 1, <empty string>, null
}

Помните, что o => Int32.TryParse(...) является просто сокращением для создания делегата, который просто принимает o в качестве параметра и возвращает Int32.TryParse(...). Вы можете заставить его делать все, что захотите, если оно по-прежнему является синтаксически правильным методом с правильной сигнатурой (например, все пути кода возвращают int)