Chuỗi không chứa phần tử phù hợp


112

Tôi có một ứng dụng asp.net trong đó tôi đang sử dụng linq để thao tác dữ liệu. Trong khi chạy, tôi nhận được ngoại lệ "Chuỗi không chứa phần tử phù hợp".

if (_lstAcl.Documents.Count > 0)
{
    for (i = 0; i <= _lstAcl.Documents.Count - 1; i++)
    {
        string id = _lstAcl.Documents[i].ID.ToString();                           
        var documentRow = _dsACL.Documents.First(o => o.ID == id);
        if (documentRow !=null)
        {

            _lstAcl.Documents[i].Read = documentRow.Read;
            _lstAcl.Documents[i].ReadRule = documentRow.ReadRule;

            _lstAcl.Documents[i].Create= documentRow.Create;
            _lstAcl.Documents[i].CreateRule = documentRow.CreateRule;

            _lstAcl.Documents[i].Update = documentRow.Update;
            _lstAcl.Documents[i].UpdateRule = documentRow.UpdateRule;

            _lstAcl.Documents[i].Delete = documentRow.Delete;
            _lstAcl.Documents[i].DeleteRule = documentRow.DeleteRule;
        }
    }
}

Câu trả lời:


220

Chà, tôi hy vọng rằng dòng này sẽ tạo ra ngoại lệ:

var documentRow = _dsACL.Documents.First(o => o.ID == id)

First()sẽ ném ra một ngoại lệ nếu nó không thể tìm thấy bất kỳ phần tử phù hợp nào. Giả sử bạn đang kiểm tra null ngay sau đó, có vẻ như bạn muốn FirstOrDefault(), giá trị này trả về giá trị mặc định cho loại phần tử (là null cho các loại tham chiếu) nếu không tìm thấy mục phù hợp:

var documentRow = _dsACL.Documents.FirstOrDefault(o => o.ID == id)

Các tùy chọn khác cần xem xét trong một số trường hợp là Single()(khi bạn tin rằng có chính xác một phần tử phù hợp) và SingleOrDefault()(khi bạn tin rằng có chính xác một hoặc không có phần tử phù hợp). Tôi nghi ngờ đó FirstOrDefaultlà lựa chọn tốt nhất trong trường hợp cụ thể này, nhưng dù sao thì cũng đáng để biết về những cái khác.

Mặt khác, có vẻ như bạn thực sự có thể sẽ tốt hơn nếu tham gia ở đây ngay từ đầu. Nếu bạn không quan tâm rằng nó sẽ thực hiện tất cả các trận đấu (thay vì chỉ trận đấu đầu tiên), bạn có thể sử dụng:

var query = from target in _lstAcl.Documents
            join source in _dsAcl.Document
            where source.ID.ToString() equals target.ID
            select new { source, target };
foreach (var pair in query)
{
    target.Read = source.Read;
    target.ReadRule = source.ReadRule;
    // etc
}

Đó là IMO đơn giản hiệu quả hơn.

Thậm chí nếu bạn làm quyết định để giữ cho vòng lặp, tôi có một vài gợi ý:

  • Loại bỏ bên ngoài if. Bạn không cần nó, vì nếu Count bằng 0 thì phần thân của vòng lặp for sẽ không bao giờ thực thi
  • Sử dụng các giới hạn trên dành riêng cho các vòng lặp - chúng dễ thành ngữ hơn trong C #:

    for (i = 0; i < _lstAcl.Documents.Count; i++)
  • Loại bỏ các biểu hiện phụ phổ biến:

    var target = _lstAcl.Documents[i];
    // Now use target for the rest of the loop body
  • Nếu có thể, hãy sử dụng foreachthay vì forbắt đầu bằng:

    foreach (var target in _lstAcl.Documents)

39

Sử dụng FirstOrDefault . First sẽ không bao giờ trả về null - nếu nó không thể tìm thấy một phần tử phù hợp, nó sẽ ném ra ngoại lệ mà bạn đang thấy.

_dsACL.Documents.FirstOrDefault(o => o.ID == id);

19
Chỉ cần làm rõ một chút - Nói chung, First có thể trả về null, nếu vị từ của bạn khớp với các giá trị null. Nó chỉ không thể trả về null ở đây, như o.IDsẽ ném một NullReferenceException trên một giá trị null.
Jon Skeet

11

Từ thư viện MSDN:

Các First<TSource>(IEnumerable<TSource>)phương pháp ném một ngoại lệ nếu nguồn không chứa yếu tố. Thay vào đó, để trả về giá trị mặc định khi chuỗi nguồn trống, hãy sử dụng FirstOrDefaultphương pháp này.


0

Đối với những người gặp phải sự cố này khi tạo bộ điều khiển thông qua menu ngữ cảnh, việc mở lại Visual Studio với tư cách quản trị viên đã khắc phục sự cố này.


-4

Có thể sử dụng Where () trước First () có thể giúp bạn, vì vấn đề của tôi đã được giải quyết trong trường hợp này.

var documentRow = _dsACL.Documents.Where(o => o.ID == id).FirstOrDefault();

3
Điều thực sự đã giúp bạn ở đây là sử dụng .FirstOrDefault () thay vì .First () - sử dụng .Where (o => o.ID == id) .FirstOrDefault () và .FirstOrDefault (o => o.ID == id ) sẽ giống hệt nhau.
pwdst

@pwdst sử dụng điều kiện trong mệnh đề Where và sau đó là FirstOrDefault mà không có bất kỳ biểu thức lambda nào.
Elnaz
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.