【问题标题】:Linq code to select one item选择一项的 Linq 代码
【发布时间】:2011-10-18 15:26:23
【问题描述】:

我发现自己写了很多这样的代码来选择一个匹配的项目

var item = (from x in Items where x.Id == 123 select x).First();

有没有一种更简洁的方法,或者这是否像我将要得到的那样简洁?

编辑:应该说“使用 linq 语法的更简洁的方式”。我已经知道 lambda 语法,并且开始看起来这实际上是唯一的方法。不过我确实得到了一些有用的信息,所以感谢所有回复的人。

【问题讨论】:

  • 我个人避免Single()SingleOrDefault()如果我知道数据已经是唯一的(例如来自具有该约束的数据库等),因为Single()强制它扫描其余部分列表中找到可能的重复项,但这就​​是我。如果此时需要强制执行唯一性,请使用Single() family,如果不需要,请使用First() family。

标签: c# linq


【解决方案1】:

看你对 linq 查询语法的喜欢程度,你可以直接使用扩展方法,比如:

var item = Items.First(i => i.Id == 123);

如果您不想在列表为空时引发错误,请使用 FirstOrDefault 返回元素类型的默认值(null 用于引用类型):

var item = Items.FirstOrDefault(i => i.Id == 123);

if (item != null)
{
    // found it
}

Single()SingleOrDefault() 也可以使用,但是如果您正在从数据库或已经保证唯一性的东西中读取,我不会打扰,因为它必须扫描列表以查看是否有任何重复和抛出。 First()FirstOrDefault() 在第一场比赛中停止,所以他们更有效率。

First()Single() 家族中,这是他们投掷的地方:

  • First() - 如果为空/未找到则抛​​出,如果重复则不抛出
  • FirstOrDefault() - 如果为空/未找到则返回默认值,如果重复则不抛出
  • Single() - 如果为空/未找到则抛​​出,如果存在重复则抛出
  • SingleOrDefault() - 如果为空/未找到则返回默认值,如果存在重复则抛出

【讨论】:

  • 我认为您在那里缺少两个等号。应该是i.Id == 123
【解决方案2】:

FirstOrDefaultSingleOrDefault 可能有用,具体取决于您的场景,以及您是要处理零个还是多个匹配:

FirstOrDefault:返回序列的第一个元素,如果没有找到元素,则返回默认值。

SingleOrDefault:返回序列的唯一元素,或默认值 如果序列为空,则为值;如果此方法抛出异常 序列中有多个元素

我不知道这在 linq 'from' 查询中是如何工作的,但在 lambda 语法中它看起来像这样:

var item1 = Items.FirstOrDefault(x => x.Id == 123);
var item2 = Items.SingleOrDefault(x => x.Id == 123);

【讨论】:

  • 哪一个在 DB 时间方面效率最高?如果我有一个 varchar,我想要一个完全匹配但可能没有?
  • 接受的答案完全解决了这个问题,但本质上,FirstOrDefault 会在找到匹配项后立即停止,但 SingleOrDefault 必须检查整个列表以确保有完全匹配
【解决方案3】:

这些是首选方法:

var item = Items.SingleOrDefault(x => x.Id == 123);

或者

var item = Items.Single(x => x.Id == 123);

【讨论】:

  • 谢谢 - 所以在这种情况下没有 linq 表示法,我需要使用 lambdas?
  • 这很好。我并没有真正使用过很多 linq,所以我不确定我是否知道这些方法。
  • 单一方法检查返回值是否唯一。因此,如果您的收藏很大,则可能需要很多时间。第一个方法只返回与谓词匹配的第一个元素。
  • @wageoghe James 的回答不使用 linq - Single 和 SingleOrDefault 方法是 IEnumerable 实现的一部分。
【解决方案4】:

只是为了让某人的生活更轻松,带有 lambda 表达式的 linq 查询

(from x in Items where x.Id == 123 select x).FirstOrDefault();

确实会导致 SQL 查询带有 select top (1) 在里面。

【讨论】:

    【解决方案5】:

    这可以更好地概括为。

    var item = Items.First(x => x.Id == 123);

    您的查询当前正在收集可枚举中的所有结果(可能不止一个),然后从 那个 集合中获取第一个结果,做的工作超出了必要的范围。

    Single/SingleOrDefault 是值得的,但前提是您要遍历整个集合并验证匹配项是否唯一以及选择该匹配项。无论实际存在多少重复项,First/FirstOrDefault 只会获取第一个匹配项并离开。

    【讨论】:

      【解决方案6】:

      您可以使用扩展方法语法:

      var item = Items.Select(x => x.Id == 123).FirstOrDefault();
      

      除此之外,我不确定如果不编写自己的专用“First”和“FirstOrDefault”扩展方法,您可以获得多少更简洁。

      【讨论】:

      • 我不认为这是预期的行为。这个 Select 指令返回(实际上没有,但它选择返回)一个 bool 集合,一个对应于 Items 的每个元素,作为 item 返回的第一个,它变成了一个简单的 bool。使用 Chris Hannon 的解决方案
      • 也许你的意思是Where 而不是Select,这已经说明了,但这个答案是不正确的。 C# 中的 Select 将结果更改为 IEnumerable,因此您将获得第一项 x.Id == 123bool
      【解决方案7】:

      我会告诉你什么对我有用:

      int id = int.Parse(insertItem.OwnerTableView.DataKeyValues[insertItem.ItemIndex]["id_usuario"].ToString());
      
      var query = user.First(x => x.id_usuario == id);
      tbUsername.Text = query.username;
      tbEmail.Text = query.email;
      tbPassword.Text = query.password;
      

      我的 id 是我要查询的行,在这种情况下,我是从 radGrid 获取的,然后我用它来查询,但是此查询返回一行,然后您可以将从查询中获得的值分配给文本框,或任何东西,我必须将它们分配给文本框。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2016-12-25
        • 2012-02-11
        • 2013-06-29
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多