Linq代码选择一项


105

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

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

有没有更干净的方法可以做到?还是像我将要得到的那样简洁?

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


5
我个人避免Single()并且SingleOrDefault()如果我知道数据已经是唯一的(例如,来自具有该约束的数据库等),因为Single()它会强制其扫描列表的其余部分以查找可能的重复项,但这就​​是我。如果此时需要增强唯一性,请使用Single()家庭,否则请使用First()家庭。
詹姆斯·迈克尔·黑尔

Answers:


176

根据您对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() -如果为空/未找到,则返回默认值;如果存在重复项,则返回

1
我认为您在那里缺少两个等号。应该是i.Id == 123
davehale23

18

根据您的情况以及是否要处理零个或多个匹配项,FirstOrDefaultSingleOrDefault可能有用。

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

SingleOrDefault:返回序列的唯一元素;如果序列为空,则返回默认值;否则返回默认值。如果序列中有多个元素,则此方法将引发异常

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

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

就数据库时间而言,哪一个最有效?如果我有一个varchar,我想精确匹配,但是可能没有?
Piotr Kula

2
接受的答案已全部解决,但从本质上讲,FirstOrDefault会在找到匹配项后立即停止,但SingleOrDefault必须检查整个列表以确保完全匹配。
斯图尔特(Stuartd)

12

这些是首选方法:

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

要么

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

谢谢-因此在这种情况下没有linq表示法,我需要使用lambda吗?
Mikey Hogarth

很好 我还没有真正使用过linq,所以我不确定我是否知道这些方法。
wageoghe

1
单一方法检查返回值是否唯一。因此,如果您的收藏很大,则可能要花费很多时间。First方法仅返回与谓词匹配的第一个元素。
meziantou 2011年

@wageoghe James的答案不使用linq-Single和SingleOrDefault方法是IEnumerable实现的一部分。
Mikey Hogarth

12

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

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

确实会导致其中带有的SQL查询 select top (1)


9

最好可以归结为这一点。

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

您的查询当前正在收集可枚举中的所有结果(可能有多个),然后从中获取第一个结果集合中,完成了不必要的工作。

Single / SingleOrDefault是值得的,但是仅当您要遍历整个集合并除了选择该匹配项之外,还要验证该匹配项是否唯一时,才值得。无论实际存在多少重复项,First / FirstOrDefault都将采用第一个匹配项并离开。


4

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

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

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


我不认为这是预期的行为。该Select指令返回(实际上不,但是选择返回)布尔值的集合,每个Item元素一个,一个作为item返回的值的第一个元素,就变成布尔值。使用克里斯·汉农的解决​​方案
莱昂纳多·达加

也许您的意思是Where与相对Select,它已经被陈述过了,但是这个答案是不正确的。在c#中选择将结果更改为IEnumerable <bool>,因此您将获得bool第一项的x.Id == 123
答案

2

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

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获取的,然后使用它进行查询,但是此查询返回一行,然后您可以将从查询中获取的值分配给文本框,或其他,我不得不将它们分配给文本框。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.