18

某种:

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

如果 o.Note 是 "" 或不是int.

我该怎么做?

4

5 回答 5

31

使用 C#7 或更高版本的每个人都滚动到底部,其他人都可以阅读原始答案:


是的,如果您将正确的参数传递给int.TryParse. 两个重载都采用intasout参数并在内部使用解析值对其进行初始化。所以像这样:

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

它比使用 inint.TryParse作为 out 参数的局部变量更干净。

Eric Lippert 评论了我的另一个答案,他举了一个例子,当它可能会受伤时:

C# LINQ:如何将 string("[1, 2, 3]") 解析为数组?


更新,这已经改变了 C#7。现在您可以在使用out参数的地方直接声明变量:

Documenti = Documenti
.OrderBy(o => string.IsNullOrEmpty(o.Note))
.ThenBy(o => Int32.TryParse(o.Note, out int note)) 
.ToList();
于 2013-05-17T16:00:40.457 回答
4
Documenti = Documenti.OrderBy(o =>
        int.TryParse(o.Note, out int val)
            ? val
            : int.MaxValue /* or int.MinValue */
    ).ToList();

int.MaxValue注意:在和之间切换int.MinValue会将空值放在列表的前面或末尾。

编辑:2020-02-07 使用 C# 7 中引入的内联输出变量

于 2013-05-17T15:54:34.370 回答
3

您实际上可以在 lambda 表达式中放置更复杂的逻辑:

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

于 2013-05-17T16:03:43.690 回答
2

这不会产生预期的结果 b/cTryParse返回 abool而不是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();

你也可以内联,但是,我认为一个单独的方法使代码更具可读性。我确信编译器会内联它,如果它是一种优化。

于 2013-05-17T15:53:13.043 回答
1

C# 7 有一些新特性使这变得更加容易

var ints = from a in str.Split(',').Select(s=> new { valid = int.TryParse(s, out int i), result = i })
           where  a.valid
           select a.result;

或者当您专门询问排序时

var ints = from a in str.Split(',')
           orderby (int.TryParse(s, out int i) ? i : 0 )
           select a.result;
于 2018-06-14T12:28:57.517 回答