First FirstOrDefault Last LastOrDefault Single 和 SingleOrDefault

所有六种方法都返回序列类型的单个值,并且可以使用或不使用谓词来调用。

根据与 predicate 匹配的元素数量,或者如果没有提供 predicate,源序列中的元素数量,它们的行为如下:

第一()

  • 返回序列的第一个元素,或与提供的 predicate 匹配的第一个元素。
  • 如果序列不包含任何元素,则会抛出 InvalidOperationException,并显示以下消息:Sequence not no elements
  • 如果序列不包含与提供的 predicate 匹配的元素,则抛出 InvalidOperationException,并显示消息 Sequence contains no matching element

// Returns "a":
new[] { "a" }.First();

// Returns "a":
new[] { "a", "b" }.First();

// Returns "b":
new[] { "a", "b" }.First(x => x.Equals("b"));

// Returns "ba":
new[] { "ba", "be" }.First(x => x.Contains("b"));

// Throws InvalidOperationException:
new[] { "ca", "ce" }.First(x => x.Contains("b"));

// Throws InvalidOperationException:
new string[0].First();

.NET 小提琴现场演示

FirstOrDefault()

  • 返回序列的第一个元素,或与提供的 predicate 匹配的第一个元素。
  • 如果序列不包含元素,或者没有与提供的 predicate 匹配的元素,则使用 default(T) 返回序列类型的默认值。

// Returns "a":
new[] { "a" }.FirstOrDefault();

// Returns "a":
new[] { "a", "b" }.FirstOrDefault();

// Returns "b":
new[] { "a", "b" }.FirstOrDefault(x => x.Equals("b"));

// Returns "ba":
new[] { "ba", "be" }.FirstOrDefault(x => x.Contains("b"));

// Returns null:
new[] { "ca", "ce" }.FirstOrDefault(x => x.Contains("b"));

// Returns null:
new string[0].FirstOrDefault();

.NET 小提琴现场演示

持续()

  • 返回序列的最后一个元素,或与提供的 predicate 匹配的最后一个元素。
  • 如果序列不包含任何元素,则抛出 InvalidOperationException,并显示消息 Sequence contains no elements
  • 如果序列不包含与提供的 predicate 匹配的元素,则抛出 InvalidOperationException,并显示消息 Sequence contains no matching element

// Returns "a":
new[] { "a" }.Last();

// Returns "b":
new[] { "a", "b" }.Last();

// Returns "a":
new[] { "a", "b" }.Last(x => x.Equals("a"));

// Returns "be":
new[] { "ba", "be" }.Last(x => x.Contains("b"));

// Throws InvalidOperationException:
new[] { "ca", "ce" }.Last(x => x.Contains("b"));

// Throws InvalidOperationException:
new string[0].Last(); 

LastOrDefault()

  • 返回序列的最后一个元素,或与提供的 predicate 匹配的最后一个元素。
  • 如果序列不包含元素,或者没有与提供的 predicate 匹配的元素,则使用 default(T) 返回序列类型的默认值。

// Returns "a":
new[] { "a" }.LastOrDefault();

// Returns "b":
new[] { "a", "b" }.LastOrDefault();

// Returns "a":
new[] { "a", "b" }.LastOrDefault(x => x.Equals("a"));

 // Returns "be":
new[] { "ba", "be" }.LastOrDefault(x => x.Contains("b"));

// Returns null:
new[] { "ca", "ce" }.LastOrDefault(x => x.Contains("b")); 

// Returns null:
new string[0].LastOrDefault();

单()

  • 如果序列恰好包含一个元素,或恰好一个元素与提供的 predicate 匹配,则返回该元素。
  • 如果序列不包含任何元素,或者没有与提供的 predicate 匹配的元素,则抛出 InvalidOperationException,并显示消息 Sequence contains no elements
  • 如果序列包含多个元素,或者多个元素与提供的 predicate 匹配,则会抛出 InvalidOperationException,并显示消息“Sequence 包含多个元素”。
  • 注意: 为了评估序列是否只包含一个元素,最多必须枚举两个元​​素。

// Returns "a":
new[] { "a" }.Single();

// Throws InvalidOperationException because sequence contains more than one element:
new[] { "a", "b" }.Single();

// Returns "b":
new[] { "a", "b" }.Single(x => x.Equals("b"));

// Throws InvalidOperationException:
new[] { "a", "b" }.Single(x => x.Equals("c"));

// Throws InvalidOperationException:
new string[0].Single(); 

// Throws InvalidOperationException because sequence contains more than one element:
new[] { "a", "a" }.Single();

SingleOrDefault()

  • 如果序列恰好包含一个元素,或恰好一个元素与提供的 predicate 匹配,则返回该元素。
  • 如果序列不包含元素,或者没有与提供的 predicate 匹配的元素,则返回 default(T)
  • 如果序列包含多个元素,或者多个元素与提供的 predicate 匹配,则会抛出 InvalidOperationException,并显示消息“Sequence 包含多个元素”。
  • 如果序列不包含与提供的 predicate 匹配的元素,则使用 default(T) 返回序列类型的默认值。
  • 注意: 为了评估序列是否只包含一个元素,最多必须枚举两个元​​素。

// Returns "a":
new[] { "a" }.SingleOrDefault();

// returns "a"
new[] { "a", "b" }.SingleOrDefault(x => x == "a"); 

// Returns null:
new[] { "a", "b" }.SingleOrDefault(x => x == "c");

// Throws InvalidOperationException:
new[] { "a", "a" }.SingleOrDefault(x => x == "a");

// Throws InvalidOperationException:
new[] { "a", "b" }.SingleOrDefault();

// Returns null:
new string[0].SingleOrDefault();

建议

  • 虽然你可以使用 FirstOrDefaultLastOrDefaultSingleOrDefault 来检查序列是否包含任何项目,但 AnyCount 更可靠。这是因为来自这三种方法之一的 default(T) 的返回值不能证明序列是空的,因为序列的第一个/最后一个/单个元素的值同样可以是 default(T)

  • 确定哪种方法最符合你的代码目的。例如,仅当你必须确保集合中的单个项目与你的谓词匹配时才使用 Single - 否则请使用 First; 如果序列有多个匹配元素,则 Single 会抛出异常。这当然也适用于“* OrDefault”-counterparts。

  • 关于效率:尽管确保通过查询返回的项目(Single)或者只有一个或零(SingleOrDefault)项目通常是合适的,但这两种方法都需要更多,通常是整个集合进行检查以确保查询没有第二个匹配。这与例如 First 方法的行为不同,该方法在找到第一个匹配后可以得到满足。