Khi nào nên sử dụng. Đầu tiên và khi nào nên sử dụng. Khát vọng với LINQ?


824

Tôi đã tìm kiếm xung quanh và thực sự không tìm thấy câu trả lời rõ ràng khi nào bạn muốn sử dụng .Firstvà khi nào bạn muốn sử dụng .FirstOrDefaultvới LINQ.

  • Khi nào bạn muốn sử dụng .First? Chỉ khi nào bạn muốn bắt ngoại lệ nếu không có kết quả nào được trả về?

    var result = List.Where(x => x == "foo").First();
  • Và khi nào bạn muốn sử dụng .FirstOrDefault? Khi bạn luôn muốn loại mặc định nếu không có kết quả?

    var result = List.Where(x => x == "foo").FirstOrDefault();
  • Và đối với vấn đề đó, còn Take?

    var result = List.Where(x => x == "foo").Take(1);

86
.First.FirstOrDefaultcả hai đều lấy các vị từ làm đối số, do đó var result = List.Where(x => x == "foo").First();có thể được viết lại thànhvar result = List.First(x => x == "foo");
Rian Schmits

59
Đừng quên xem xét SingleSingleOrDefault. Tôi ghét khi mọi người sử dụng Firstkhi họ thực sự có ý nghĩa Single; )
BartoszKP

19
Single hoặc SingleOrDefault sẽ đưa ra một ngoại lệ nếu có nhiều hơn một phần tử được trả về! Tôi nghĩ FirstOrDefault tốt hơn trong hầu hết các trường hợp phổ biến!
Eric Draven

21
Vấn đề là khi bạn mong đợi một kết quả Đơn lẻ, bạn nên nói như vậy và ngoại lệ cho thấy logic của bạn thất bại.
NetMage

1
Cũng xem xét rằng việc sử dụng .FirstOrDefault()luôn mang đến cho bạn cơ hội để đưa ra một ngoại lệ có ý nghĩa hơn. Nếu một ngoại lệ chuỗi được ném và nhiều hơn một .First()trong một phương thức, có thể khó nhận ra câu lệnh nào là vấn đề.
StingyJack

Câu trả lời:


807

Tôi sẽ sử dụng First()khi tôi biết hoặc mong đợi chuỗi có ít nhất một phần tử. Nói cách khác, khi xảy ra trường hợp đặc biệt là chuỗi trống.

Sử dụng FirstOrDefault()khi bạn biết rằng bạn sẽ cần kiểm tra xem có yếu tố nào hay không. Nói cách khác, khi nó là hợp pháp cho chuỗi trống. Bạn không nên dựa vào xử lý ngoại lệ cho việc kiểm tra. (Đó là thực tế xấu và có thể làm tổn thương hiệu suất).

Cuối cùng, sự khác biệt giữa First()Take(1)First()trả về chính phần tử đó, trong khi Take(1)trả về một chuỗi các phần tử có chứa chính xác một phần tử.


4
@driis - Tôi tưởng tượng chúng ta có thể sử dụng câu thần chú của hướng dẫn ngoại lệ đặc biệt khi lựa chọn giữa First và FirstOrDefault. Cảm ơn câu trả lời rõ ràng.
Tàu điện ngầm Smurf

5
Điều duy nhất tôi muốn thêm là nếu giá trị mặc định cho loại bạn đang chọn có thể là giá trị hợp lệ, ví dụ kết quả của bạn có thể là giá trị int 0, thì xử lý ngoại lệ dường như là cách tốt nhất để xử lý điều này .
PeterBelm

25
Không có gì, tôi đã tìm thấy một cách tốt hơn để thực hiện điều đó, sử dụng:
Default IfEmpty

5
Take không trả về chính xác một phần tử, nó trả về tối đa một phần tử (tất nhiên nếu bạn chỉ định 1 phần tử). Nó cũng có thể trả về 0 phần tử, nếu chuỗi ban đầu trống.
SPIRiT_1984

3
@RoyiNamir, có trong bối cảnh của câu hỏi mà tham số cần lấy là 1. Tôi cũng lưu ý rằng trong parens ngay sau câu đó.
driis

272

.Firstsẽ ném một ngoại lệ khi không có kết quả. .FirstOrDefaultsẽ không, nó sẽ trả về null (loại tham chiếu) hoặc giá trị mặc định của loại giá trị. (ví dụ như 0đối với một int.) Câu hỏi ở đây không phải là khi bạn muốn loại mặc định, mà hơn thế nữa: Bạn có sẵn sàng xử lý một ngoại lệ hoặc xử lý một giá trị mặc định không? Vì các trường hợp ngoại lệ phải là ngoại lệ, FirstOrDefaultđược ưu tiên khi bạn không chắc chắn liệu mình có nhận được kết quả từ truy vấn của mình không. Khi logic dữ liệu nên ở đó, xử lý ngoại lệ có thể được xem xét.

Skip()Take()thường được sử dụng khi thiết lập phân trang trong kết quả. (Giống như hiển thị 10 kết quả đầu tiên và 10 kết quả tiếp theo trên trang tiếp theo, v.v.)

Hi vọng điêu nay co ich.


5
@Jeroen - điểm tốt trong các trường hợp sử dụng tốt hơn để sử dụng Skip / Take.
Tàu điện ngầm Smurf

4
+1 để giải thích .FirstOrDefaultsẽ trả về null cho các loại tham chiếu. Tôi đã nhầm lẫn về một đối tượng "mặc định" sẽ là gì. Câu trả lời này đã xóa nó lên.
Mike Cheesne

115

.First()thay vào đó sẽ đưa ra một ngoại lệ nếu không có hàng nào được trả về, trong khi đó .FirstOrDefault()sẽ trả về giá trị mặc định ( NULLcho tất cả các loại tham chiếu).

Vì vậy, nếu bạn đã chuẩn bị và sẵn sàng xử lý một ngoại lệ có thể, .First()thì tốt thôi. Nếu bạn muốn kiểm tra giá trị trả lại cho != nulldù sao, thì đó .FirstOrDefault()là sự lựa chọn tốt hơn của bạn.

Nhưng tôi đoán đó cũng là một chút sở thích cá nhân. Sử dụng bất cứ điều gì có ý nghĩa hơn với bạn và phù hợp với phong cách mã hóa của bạn tốt hơn.


66

Đầu tiên()

  1. Trả về phần tử đầu tiên của chuỗi.
  2. Nó đưa ra một lỗi khi không có phần tử nào trong kết quả hoặc nguồn là null.
  3. bạn nên sử dụng nó, Nếu có nhiều hơn một yếu tố được mong đợi và bạn chỉ muốn yếu tố đầu tiên.

FirstOrDefault ()

  1. Trả về phần tử đầu tiên của chuỗi hoặc giá trị mặc định nếu không tìm thấy phần tử nào.
  2. Nó ném một lỗi Chỉ khi nguồn là null.
  3. bạn nên sử dụng nó, Nếu có nhiều hơn một yếu tố được mong đợi và bạn chỉ muốn yếu tố đầu tiên. Cũng tốt nếu kết quả là trống rỗng.

Chúng tôi có một bảng UserInfos, có một số bản ghi như dưới đây. Trên cơ sở bảng này bên dưới, tôi đã tạo ví dụ ...

Bảng UserInfo

Cách sử dụng First ()

var result = dc.UserInfos.First(x => x.ID == 1);

Chỉ có một bản ghi trong đó ID == 1. Nên trả lại bản ghi này
ID: 1 Tên: Manish Họ: Dubey Email: xyz@xyz.com

var result = dc.UserInfos.First(x => x.FName == "Rahul");   

Có nhiều bản ghi trong đó FName == "Rahul". Hồ sơ đầu tiên nên được trả lại.
ID: 7 Tên: Rahul Tên cuối cùng: Sharma Email: xyz1@xyz.com

var result = dc.UserInfos.First(x => x.ID ==13);

Không có bản ghi với ID == 13. Sẽ xảy ra lỗi.
UnlimitedOperationException: Trình tự không chứa phần tử

Cách sử dụng FirstOrDefault ()

var result = dc.UserInfos.FirstOrDefault(x => x.ID == 1);

Chỉ có một bản ghi trong đó ID == 1. Nên trả lại bản ghi này
ID: 1 Tên: Manish Họ: Dubey Email: xyz@xyz.com

var result = dc.UserInfos.FirstOrDefault(x => x.FName == "Rahul");

Có nhiều bản ghi trong đó FName == "Rahul". Hồ sơ đầu tiên nên được trả lại.
ID: 7 Tên: Rahul Tên cuối cùng: Sharma Email: xyz1@xyz.com

var result = dc.UserInfos.FirstOrDefault(x => x.ID ==13);

Không có bản ghi với ID == 13. Giá trị trả về là null

Hy vọng nó sẽ giúp bạn hiểu khi nào nên sử dụng First()hay FirstOrDefault().


4
Theo tôi, tuyên bố "Một lỗi nên xảy ra." theo FirstOrDefault () - ví dụ thứ ba là sai lệch.
Jannik

Xin chào, bạn giải thích rõ, nhưng tôi hơi bối rối khi lấy dữ liệu từ tham gia và khi ID không tồn tại trong bảng khóa ngoại tại thời điểm đó được sử dụng? Hiện tại, tôi đang sử dụng First () nhưng sau khi đọc câu trả lời của bạn, tôi không biết. Xin hãy giúp đỡ
Brijesh Mavani

20

Trước hết, Takelà một phương pháp hoàn toàn khác. Nó trả về một IEnumerable<T>và không một T, vì vậy đó là ra.

Giữa FirstFirstOrDefault, bạn nên sử dụng Firstkhi bạn chắc chắn rằng một phần tử tồn tại và nếu nó không tồn tại thì có lỗi.

Nhân tiện, nếu chuỗi của bạn chứa default(T)các phần tử (ví dụ null) và bạn cần phân biệt giữa phần tử trống và phần tử đầu tiên null, bạn không thể sử dụng FirstOrDefault.


2
@Mehrdad - điểm tuyệt vời, re: .Đầu tiên trả về IEnumerable và khi không sử dụng FirstOrDefault.
Tàu điện ngầm Smurf

15

Đầu tiên:

  • Trả về phần tử đầu tiên của chuỗi
  • Ngoại lệ ném: Không có yếu tố nào trong kết quả
  • Sử dụng khi: Khi có nhiều hơn 1 phần tử được mong đợi và bạn chỉ muốn phần tử đầu tiên

Đầu tiên xác định:

  • Trả về phần tử đầu tiên của chuỗi hoặc giá trị mặc định nếu không tìm thấy phần tử nào
  • Ném ngoại lệ: Chỉ khi nguồn là null
  • Sử dụng khi: Khi có nhiều hơn 1 phần tử được mong đợi và bạn chỉ muốn phần tử đầu tiên. Ngoài ra nó là ok cho kết quả để trống

Từ: http://www.technicaloverload.com/linq-single-vs-singleordefault-vs-first-vs-firstordefault/


10

Một điểm khác biệt cần lưu ý là nếu bạn gỡ lỗi một ứng dụng trong môi trường Sản xuất, bạn có thể không có quyền truy cập vào số dòng, do đó, việc xác định .First()câu lệnh cụ thể nào trong phương thức đã ném ngoại lệ có thể khó khăn.

Thông báo ngoại lệ cũng sẽ không bao gồm bất kỳ biểu thức Lambda nào bạn có thể đã sử dụng, điều này sẽ khiến mọi vấn đề trở nên khó khăn hơn.

Đó là lý do tại sao tôi luôn sử dụng FirstOrDefault()mặc dù tôi biết một mục rỗng sẽ tạo thành một tình huống đặc biệt.

var customer = context.Customers.FirstOrDefault(i => i.Id == customerId);
if (customer == null)
{
   throw new Exception(string.Format("Can't find customer {0}.", customerId));
}

5

Đầu tiên()

Khi bạn biết rằng kết quả đó chứa nhiều hơn 1 phần tử dự kiến ​​và bạn chỉ nên là phần tử đầu tiên của chuỗi.

FirstOrDefault ()

FirstOrDefault () giống như First () ngoại trừ việc, nếu không có phần tử nào khớp với điều kiện đã chỉ định thì nó trả về giá trị mặc định của kiểu bộ sưu tập chung bên dưới. Nó không ném UnlimitedOperationException nếu không tìm thấy phần tử nào. Nhưng tập hợp các phần tử hoặc một chuỗi là null hơn nó ném một ngoại lệ.


Xin chào, bạn giải thích rõ, nhưng tôi hơi bối rối khi lấy dữ liệu từ tham gia và khi ID không tồn tại trong bảng khóa ngoại tại thời điểm đó được sử dụng? Hiện tại, tôi đang sử dụng First () nhưng sau khi đọc câu trả lời của bạn, tôi không biết. Xin hãy giúp đỡ
Brijesh Mavani

4

Loại hàm này thuộc về toán tử phần tử. Một số toán tử phần tử hữu ích được định nghĩa dưới đây.

  1. Đầu tiên / FirstOrDefault
  2. Cuối cùng / LastOrDefault
  3. Đơn / SingleOrDefault

Chúng tôi sử dụng các toán tử phần tử khi chúng tôi cần chọn một phần tử từ một chuỗi dựa trên một điều kiện nhất định. Đây là một ví dụ.

  List<int> items = new List<int>() { 8, 5, 2, 4, 2, 6, 9, 2, 10 };

Toán tử First () trả về phần tử đầu tiên của chuỗi sau khi thỏa mãn điều kiện. Nếu không tìm thấy phần tử nào thì nó sẽ ném ngoại lệ.

int result = items.Where (item => item == 2) .Đầu tiên ();

Toán tử FirstOrDefault () trả về phần tử đầu tiên của chuỗi sau khi thỏa mãn điều kiện. Nếu không tìm thấy phần tử nào thì nó sẽ trả về giá trị mặc định của loại đó.

int result1 = items.Where (item => item == 2) .irstirstDefDef ();


giải thích độc đáo với một ví dụ dễ hiểu.
Arslan Bhatti

3

Tôi đã tìm thấy một trang web xuất hiện để giải thích sự cần thiết của FirstOrDefault
http://thepursuitofalife.com/the-linq-firstordefault-method-and-null-resultsets/
Nếu không có kết quả nào cho truy vấn và bạn muốn gọi trước () hoặc Đơn () để nhận một hàng duy nhất ... Bạn sẽ nhận được một Chuỗi Sequence không chứa ngoại lệ.

Tuyên bố miễn trừ trách nhiệm: Tôi chưa bao giờ sử dụng LINQ, vì vậy tôi xin lỗi nếu điều này không đúng.


2
someList.First(); // exception if collection is empty.
someList.FirstOrDefault(); // first item or default(Type)

Nên dùng cái nào? Nó nên được quyết định bởi logic kinh doanh, và không phải sợ thất bại ngoại lệ / chương trình.

Chẳng hạn, nếu logic kinh doanh nói rằng chúng ta không thể có giao dịch bằng 0 vào bất kỳ ngày làm việc nào (Chỉ cần giả sử). Sau đó, bạn không nên cố gắng xử lý tình huống này với một số chương trình thông minh. Tôi sẽ luôn sử dụng First () trên bộ sưu tập như vậy và để chương trình thất bại nếu có điều gì khác làm hỏng logic kinh doanh.

Mã số:

var transactionsOnWorkingDay = GetTransactionOnLatestWorkingDay();
var justNeedOneToProcess = transactionsOnWorkingDay.First(): //Not FirstOrDefault()

Tôi muốn xem ý kiến ​​của người khác về điều này.


Giá trị mặc định cho các loại tham chiếu và nullable là null.
dsa

Thất bại nhanh chóng là tốt - tuy nhiên đối với kịch bản bạn mô tả, tôi muốn xem Đầu tiên, thất bại, bắt ngoại lệ và sau đó trả về một lỗi có ý nghĩa. Like Catch (UnlimitedOperationException e) {throw new UnlimitedOperationException ("Không thể có giao dịch bằng 0 trong một ngày!", E)}; Nhưng vâng, sử dụng mặc định để tránh xử lý một vấn đề logic kinh doanh thực sự là rất xấu.
Mathieson

1

Ok để tôi cho tôi hai xu. First / Firstordefault dành cho khi bạn sử dụng hàm tạo thứ hai. Tôi sẽ không giải thích nó là gì, nhưng đó là khi bạn có khả năng luôn luôn sử dụng nó vì bạn không muốn gây ra ngoại lệ.

person = tmp.FirstOrDefault(new Func<Person, bool>((p) =>
{
    return string.IsNullOrEmpty(p.Relationship);
}));

Không chính xác. Hàm tạo đầu tiên được sử dụng rộng rãi khi bạn chỉ cần truy xuất một mục hoặc phải tránh lỗi biên dịch khi gán kết quả cho một giá trị không phải là một mảng và bạn chắc chắn truy vấn trả về chính xác một kết quả. Mặc dù có thể sử dụng hàm tạo thứ hai nhanh hơn thay vì sử dụng bổ sung .Where () (vì bạn nghĩ LINQ dừng đánh giá các mục trong danh sách sau khi tìm thấy phần đầu tiên), nó luôn dừng ở phần tử đầu tiên
usr-local-ΕΨΗΕΛΩΝ

0

Những người khác đã mô tả rất tốt sự khác biệt giữa First()FirstOrDefault(). Tôi muốn tiến thêm một bước trong việc diễn giải ngữ nghĩa của các phương pháp này. Theo tôi FirstOrDefaultđang bị lạm dụng rất nhiều. Trong phần lớn các trường hợp khi bạn lọc dữ liệu, bạn sẽ mong nhận lại được một tập hợp các phần tử khớp với điều kiện logic hoặc một phần tử duy nhất bằng mã định danh duy nhất của nó - chẳng hạn như người dùng, sách, bài đăng, v.v ... Đó là Tại sao chúng ta thậm chí có thể nói rằng đó FirstOrDefault()là mùi mã không phải vì có gì đó không đúng với nó mà vì nó được sử dụng quá thường xuyên. Bài đăng blog này khám phá các chủ đề chi tiết. IMO hầu hết thời gianSingleOrDefault() là một sự thay thế tốt hơn nhiều vì vậy hãy coi chừng sai lầm này và đảm bảo bạn sử dụng phương pháp phù hợp nhất thể hiện rõ ràng hợp đồng và kỳ vọng của bạn.


-6

linq nhiều cách để thực hiện truy vấn đơn giản trên các bộ sưu tập, chỉ cần chúng ta viết các phép nối trong sql, một bộ lọc có thể được áp dụng trước hoặc cuối tùy thuộc vào nhu cầu và sự cần thiết.

Dưới đây là một ví dụ nơi chúng ta có thể tìm thấy một phần tử có id trong bộ sưu tập. Để thêm nhiều hơn về điều này, các phương thức Đầu tiên, FirstOrDefaultlý tưởng sẽ trở lại tương tự khi một bộ sưu tập có ít nhất một bản ghi. Tuy nhiên, nếu một bộ sưu tập là ổn để trống. sau đó Firstsẽ trả về một ngoại lệ nhưng FirstOrDefaultsẽ trả về nullhoặc mặc định. Ví dụ, intsẽ trả về 0. Do đó, việc sử dụng như vậy mặc dù được cho là sở thích cá nhân, nhưng tốt hơn nên sử dụng FirstOrDefaultđể tránh xử lý ngoại lệ. đây là một ví dụ trong đó, chúng tôi chạy qua một bộ sưu tập danh sách giao dịch

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.