Вид:
Documenti = Documenti
.OrderBy(o => string.IsNullOrEmpty(o.Note))
.ThenBy(o => Int32.TryParse(o.Note))
.ToList();
Это будет "игнорировать" (не порядок, если положить конец), если o.Note "" или нет int
.
Как я могу это сделать?
Вид:
Documenti = Documenti
.OrderBy(o => string.IsNullOrEmpty(o.Note))
.ThenBy(o => Int32.TryParse(o.Note))
.ToList();
Это будет "игнорировать" (не порядок, если положить конец), если o.Note "" или нет int
.
Как я могу это сделать?
Да, вы можете, если вы передадите правильные параметры 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]" ) анализируется как массив?
int dummy;
Documenti = Documenti.OrderBy(
o => Int32.TryParse(o.Note, out dummy) ?
dummy :
Int32.MaxValue /* or Int32.MinValue */
).ToList();
Примечание. Переключение между Int32.MaxValue
и Int32.MinValue
приведет либо к пустым значениям в начале, либо в конце списка.
Это не приведет к ожидаемым результатам 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();
вы тоже можете сделать это, но я думаю, что отдельный метод делает код более читаемым. я уверен, что компилятор включит его, если это оптимизация.
В выражении лямбда вы можете поставить гораздо более сложную логику:
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
)