2011-01-28 25 views
6

Trước hết, tôi biết câu hỏi này có thể được trả lời với một câu trả lời đơn giản rằng một chuỗi rỗng không phải là một giá trị null. Ngoài ra, gần đây tôi mới phát hiện ra các toán tử diễn viên vào đầu năm qua một câu hỏi stackoverflow khác và không có nhiều kinh nghiệm với họ. Mặc dù vậy, lý do tại sao nó không hoàn toàn đơn giản là các toán tử cast khi kết hợp với toán tử kết hợp null, được tính như một giải pháp thanh lịch để xử lý các điều kiện lỗi như thiếu các phần tử hoặc các thuộc tính trong các biểu thức LINQ. Tôi bắt đầu sử dụng the approach described by ScottH in "Improving LINQ Code Smell..." và bởi ScottGu "Null coalescing operator (and using it with LINQ)" như một cách để bảo vệ khỏi dữ liệu không hợp lệ/bị thiếu theo cách súc tích và bán trang nhã. Từ những gì tôi có thể thu thập mà dường như là một trong những động cơ để đưa tất cả các quá tải cast trong các lớp LINQ ở nơi đầu tiên. Vì vậy, trong tâm trí của tôi, trường hợp sử dụng giao dịch với một giá trị còn thiếu không phải là tất cả những gì khác so với giao dịch với một sản phẩm nào và trong các bài báo được liên kết, cách tiếp cận này được lập hóa đơn như một cách tốt để xử lý tình huống.Tại sao toán tử LINQ rõ ràng có thể ném các ngoại lệ định dạng không hợp lệ lên các giá trị rỗng?

Kịch bản:

int length = (int?)elem.Attribute("Length") ?? 0; 

Nếu thuộc tính @Length là mất tích, kết quả dàn diễn viên trong một giá trị null và ?? toán tử trả về 0;

Nếu thuộc tính @Length tồn tại nhưng trống đối với các nhánh nội bộ trên int.tryparse và ném ngoại lệ định dạng. Tất nhiên cho việc sử dụng của tôi, tôi muốn nó sẽ không và sẽ chỉ đơn giản là trả về null vì vậy tôi có thể tiếp tục sử dụng cách tiếp cận này trong mã LINQ đã hơi phức tạp của tôi. Cuối cùng nó không phải là quá nhiều mà tôi không thể đưa ra một giải pháp nhưng nhiều hơn vì vậy mà tôi quan tâm để nghe nếu có một cách tiếp cận rõ ràng mà tôi đã bỏ lỡ hoặc nếu nó bất cứ ai có một cái nhìn tốt về lý do tại sao thiếu kịch bản giá trị nhưng kịch bản giá trị rỗng không.

Sửa

Dường như có một vài điểm chính tôi nên thử và nổi bật:

  • Các bài viết liên quan đến từ đội ngũ nhân viên MS mà tôi ngưỡng mộ và tìm đến để được hướng dẫn. Những bài viết này dường như đề xuất (hoặc ít nhất là gọi sự chú ý đến) một cách tiếp cận/thay thế cải tiến để đối phó với các giá trị tùy chọn

  • Trong trường hợp của tôi giá trị tùy chọn đôi khi đến dưới hình thức của thiếu yếu tố hoặc các thuộc tính nhưng cũng đến theo hình thức yếu tố hoặc các giá trị

  • phương pháp mô tả hoạt động như dự kiến ​​cho các giá trị bị mất tích nhưng không cho các giá trị rỗng

  • Mã mà theo phương pháp mô tả sản phẩm nào xuất hiện để được bảo vệ chống lại việc thiếu các giá trị tùy chọn nhưng trên thực tế là mong manh và phá vỡ trong một trường hợp cụ thể.Đó là sự xuất hiện của bảo vệ trong khi thực tế bạn vẫn có nguy cơ liên quan đến mình

  • Điều này có thể được đánh dấu bằng cách nói rằng cả hai ví dụ liên kết thất bại với một ngoại lệ thời gian chạy nếu các yếu tố mục tiêu tồn tại nhưng trống

  • Cuối cùng, có vẻ như cách tiếp cận được mô tả hoạt động tốt khi bạn có một hợp đồng tại chỗ (có thể thông qua lược đồ) để đảm bảo thành phần hoặc thuộc tính sẽ không bao giờ trống nhưng trong trường hợp hợp đồng đó không tồn tại, cách tiếp cận này là không hợp lệ và thay thế là cần thiết

+1

phương thức '.Attribute()' nào của bạn trở về? kể từ khi nào được xây dựng trong phôi gây ra một ví dụ. 'int.TryParse()'? –

+0

điều này trông giống như XAttribute từ System.Xml.Linq –

+1

@Konstantin: errr ... duck-hunting :) –

Trả lời

3

Tôi tình cờ đồng ý với hành vi đó; nếu tôi không có thuộc tính/id "id", thì tôi rất vui khi tính số đó là null, nhưng nếu nó tồn tại nhưng không phân tích, điều đó khác - và chuỗi trống hoạt động rất vài loại. Bạn sẽ phải làm điều đó bằng tay, hoặc bạn có thể thêm một phương pháp mở rộng trên XAttribute vv:

public static int? ParseInt32(this XAttribute attrib) { 
    if(attrib != null && string.IsNullOrEmpty(attrib.Value)) return null; 
    return (int?)attrib; 
} 

Note Tôi đang sử dụng các diễn viên trong nội bộ như trong khi nó rất đơn giản cho int, một .Parse sẽ là một xấu ví dụ cho DateTime v.v., sử dụng định dạng khác trong xml mà dàn diễn viên xử lý nội bộ.

+0

Rất tốt. Có lẽ tôi sẽ dùng câu trả lời này và dùng nó để thay thế cách giải quyết mà tôi đã nghĩ ra. Tôi để câu hỏi mở ra lâu hơn một chút trong trường hợp bất kỳ ai khác có thể kêu gọi và có ý kiến ​​về khía cạnh của các ví dụ về bài viết được liên kết dễ vỡ và bạn khó giải quyết vấn đề này bằng phương pháp mở rộng trong một trường hợp. nguyên bản trong khác. –

+0

@ John Tôi đồng ý rằng đối với ** thiếu **, I.e. Không có thuộc tính/phần tử như vậy, nhưng tôi * không đồng ý * lại * trống *. giống như xsd trên thực tế. –

+0

Khi bạn xem xét rằng các toán tử cast thêm (như int?) Đã được thêm vào (tôi tin) để hỗ trợ trong việc đưa ra các truy vấn LINQ dễ đọc và sử dụng hơn ... có vẻ như ý định của các lập trình viên không phải là một phần tử ** * đến một int, là để xác định nếu giá trị có thể là một int. Hơn nữa, sẽ không thiếu một giá trị (hoặc thông qua một yếu tố mất tích hoặc một phần tử trống) có vẻ như điều kiện hợp lý để trả về một null? Tôi có thể thấy một lỗi khi có dữ liệu không phải số, nhưng với phạm vi hạn chế của các toán tử này, nếu gần như có vẻ hợp lý để trả về giá trị null trên int rỗng? phôi –

1

Theo như cách giải quyết khác, tôi đã xây dựng phương thức mở rộng bên dưới. Tôi đã không nghĩ đến cách tiếp cận được mô tả bởi Marc mà sửa chữa vấn đề với một int nullable và vẫn còn sử dụng ?? toán tử để chỉ định mặc định. Rất sáng tạo và cho phép X ?? Y mẫu để tiếp tục được sử dụng. Tôi nghĩ cuối cùng tôi có thể thích cách tiếp cận của Marc bởi vì nó giữ một mẫu nhất quán trong các câu lệnh chuyển nhượng của tôi và không giới thiệu sự nhầm lẫn về cú pháp mà lời gọi TryParseInt đã xuất hiện quá nhiều như bạn đang phân tích cú pháp -1 hoặc bất cứ điều gì giá trị mặc định/dự phòng đã được cung cấp.

elem.Attribute("ID").TryParseInt(-1) 

    /// <summary> 
    /// Parses an attribute to extract an In32 value and falls back to the defaultValue should parsing fail 
    /// </summary> 
    /// <param name="defaultValue">The value to use should Int32.TryParse fail</param> 
    /// <returns>The parsed or default integer value</returns> 
    public static int TryParseInt(this XAttribute attr, int defaultValue) 
    { 
     int result; 
     if (!Int32.TryParse((string)attr, out result)) 
     { 
      // When parsing fails, use the fallback value 
      result = defaultValue; 
     } 

     return result; 
    } 
Các vấn đề liên quan