C# 中奇妙的函数 -- 2. First 和 Single -- 你是她心中的第一还是唯一?

Linq中的 First 和 Single 在实际工作中会经常看到,从字面意思上很容易明白,一个是取列表中的第一个元素,一个是取到唯一的元素。如果你想再进一步的了解,可以读读本文。

下文参考翻译自:
C#/.NET Little Wonders: First() and Single() - Similar Yet Different

First() - 返回序列中的第一个元素

事实上这个方法有四种选择:

  • First()
    • 返回序列中的第一个,如果没有元素存在就抛出异常 InvalidOperationException.
  • First(Predicate<TSource>)
    • 基于你提供的条件返回序列中的第一个,如果没有元素存在就抛出异常 InvalidOperationException.
  • FirstOrDefault()
    • 返回序列中的第一个,如果没有元素存在就返回默认的元素default(TSource).
  • FirstOrDefault(Predicate<TSource>)
    • 基于你提供的条件返回序列中的第一个,如果没有元素存在就返回默认的元素default(TSource).

First的核心思想是如果序列中存在一个以上元素的时候,就返回第一个。这也意味着当发现第一个元素的时候,被调用的这个方法就立刻退出了不会再去遍历寻找剩下的元素了。

举例看看,定义一个类:

  public sealed class Employee

 {

     public long Id { get; set; }

     public string Name { get; set; }

     public double Salary { get; set; }

 }

给他一些初始化的列表:有空的,一个元素的,多个元素的

 // 空表

var noEmployeeList = new List<Employee>();

 

// 一个元素

var oneEmployeeList = new List<Employee>

    {

        new Employee { Id = 55, Name = "Sussie Queue", Salary = 60000.50 }

    };

 

// 多个元素

var employees = new List<Employee>

    {

        new Employee { Id = 1, Name = "Jim Smith", Salary = 12345.50 },

        new Employee { Id = 7, Name = "Jane Doe", Salary = 31234.50 },

        new Employee { Id = 9, Name = "John Doe", Salary = 13923.99 },

        new Employee { Id = 13, Name = "Jim Smith", Salary = 30123.49 },        

        // ... etc ...

    };

好,当我们使用First的时候,他们会有什么结果呢?

 var first = employees.First();
var firstJohn = employees.First(e => e.Name.StartsWith("John"));
var firstDoe = employee.First(e => e.Name.EndsWith("Doe"));

另外请注意在下面的情况下会抛出异常:

 var empty = noEmployees.First();

var noMatch = employees.First(e => e.Id == 20);

最后,当我们使用带有Default的方法时,下面的情况会返回空值而不是抛出异常:

 var empty = noEmployees.FirstOrDefault();

var noMatch = employees.FirstOrDefault(e => e.Id == 20);

Single() – 有且仅有一个

 像First一样,Single 也有四种表现形式:

Single()
  • 返回序列中的唯一的元素,如果没有元素存在就抛出异常 InvalidOperationException, 如果多于一个,也抛出异常InvalidOperationException.
Single(Predicate<TSource>)
  • 基于你提供的条件返回序列中的唯一的元素,如果没有元素存在就抛出异常 InvalidOperationException, 如果多于一个,抛出异常InvalidOperationException.  SingleOrDefault()
SingleOrDefault() 返回序列中的唯一的元素,如果没有元素存在就返回默认的元素default(TSource), 如果多于一个,抛出异常InvalidOperationException . SingleOrDefault(Predicate<TSource>)
  • 基于你提供的条件返回序列中的唯一的元素,如果没有元素存在就返回默认的元素default(TSource), 如果多于一个,抛出异常InvalidOperationException.
请注意,关键的区别主要在这里: 如果有一个以上的元素,这个家族的方法会永远抛出 InvalidOperationException异常。  还要注意,这意味着,即使Single 方法得到了一个匹配的元素,它仍然有可能要扫描其余的枚举。 这可以使 Single 效率要低一点。

下面一些例子返回什么呢?

 var oneAndOnly = oneEmployeeList.Single();

var throwsOnEmpty = noEmployeeList.Single();

var throwsOnMultiple = employeeList.Single();

从下面的例子,我们看到Single 和 First 的相似性, 不同的在于满足结果的序列多于一个元素的情况

 // 得到 ID == 7 的唯一元素

var oneAndOnlyMatch = oneEmployeeList.Single(e => e.Id == 7);

 

// 抛出异常

var throwsOnNoMatches = noEmployeeList.Single(e => e.Id == 999);

 

// 抛出异常

var throwsOnMultipleMatches = employeeList.Single(e => e.Name.EndsWith("Doe"));


// 返回一个null的元素.

var defaultsOnEmpty = noEmployeeList.SingleOrDefault();

 

// 返回一个null的元素.

var defaultsOnNoMatch = noEmployeeList.SingleOrDefault(e => e.Id == 999);

结论

First 和 Single 都有一个避免当没有元素满足要求而抛出异常的选择,当你不确定想要获取的元素是否存在的时候,可以用…OrDefault(), 因为 null 可以很好的表示“找到不”。

当你不在乎是否有重复项目或者不可能有重复元素存在的时候,可以使用First; 当你想要核实是否有重复元素存在的时候当然就选择Single。

谢谢你阅读本文,更多.NET话题请到:

喜乐的ASP.NET

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值