【问题标题】:Can I use a TryParse inside Linq Comparable?我可以在 Linq Comparable 中使用 TryParse 吗?
【发布时间】:2013-05-17 15:48:50
【问题描述】:

一种:

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

如果 o.Note 是“”或不是int,那将“忽略”(不是排序,放在最后)。

我该怎么做?

【问题讨论】:

  • 你能试着用完整的句子改写这个问题吗?也许其他人会更清楚,但我不知道你在问什么。
  • 你在用这个EntityFramework

标签: c# linq


【解决方案1】:

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


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

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

clean 方法使用解析为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 因为truefalse“更大”):

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

这比使用int.TryParse 中使用的局部变量作为输出参数更简洁。

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

C# LINQ: How is string("[1, 2, 3]") parsed as an array?


更新,this has changed with C#7。现在可以在使用out参数的地方直接声明变量:

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

【讨论】:

    【解决方案2】:
    Documenti = Documenti.OrderBy(o =>
            int.TryParse(o.Note, out int val)
                ? val
                : int.MaxValue /* or int.MinValue */
        ).ToList();
    

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

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

    【讨论】:

    • @TimSchmelter 不能保证工作的是在另一个委托中引用相同的dummy 变量,例如strings.Where(s => int.TryParse(s, out dummy)).Select(s => dummy)。这不是这个答案所具有的,这里没有问题。
    • 我同意将临时变量移动到委托中可能是最佳实践,而且很容易做到。我实际上修改了我的答案来做到这一点,但后来决定回滚,因为似乎有一个很好的讨论,关于使用这样的变量是否符合规定。
    • @Servy:我只见过这些老 cmets。我已经在上面编辑了我的答案以链接到a comment of E. Lippert,他在其中表明实现细节可能不会改变,但在 LINQ 查询中使用int.TryParse 可能会导致其他不良影响。
    • @TimSchmelter 这表明它令人困惑、难以阅读/理解、糟糕的实践、未来的开发人员在重构代码时很容易意外破坏等等。这些都不能让它依赖实施细节。我绝对同意使用 Eric 将这个功能包装在一个方法中来隐藏黑盒子后面的变量突变的方法,这只是你对为什么这很重要的解释是不正确的。
    【解决方案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 =&gt; Int32.TryParse(...) 只是创建委托的简写,它只接受 o 作为参数并返回 Int32.TryParse(...)。只要它仍然是具有正确签名的语法正确方法(例如,所有代码路径都返回int),您就可以让它做任何您想做的事情

    【讨论】:

      【解决方案4】:

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

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

      【讨论】:

      • 我会让 parseNote 返回 int? 只是因为将不是 int 的东西返回为“not an int”是有意义的。如果需要,您应该仍然可以通过 .OrderByDescending(o =&gt; -parseNote(o.Note)) 使 nulls 出现在最后。
      • That won't produce the expected results b/c TryParse returns a bool rather than int 看起来他想要那个;他想将所有不是整数的项目移到最后,而不是按它们的数值排序。
      • 我提交的代码将按 int 值对对象进行排序,并将具有非 int 注释值的项目推到底部,我认为这就是所要求的。这个问题在这方面有点模糊
      【解决方案5】:

      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;
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2010-12-24
        • 2021-01-17
        • 2023-04-08
        • 1970-01-01
        • 1970-01-01
        • 2016-03-07
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多