2012-10-02 49 views
7

Tôi đang cố gắng để ngăn chặn có giá trị NULL khi tôi phân tích một tệp XML thành một đối tượng tùy chỉnh bằng cách sử dụng LINQ.C# ?? null coalescing toán LINQ

Tôi đã tìm thấy giải pháp tuyệt vời cho điều này trên Scott Gu's blog, nhưng vì một lý do nào đó, nó không hoạt động với các số nguyên với tôi. Tôi nghĩ rằng tôi đã sử dụng cú pháp tương tự nhưng có vẻ như tôi đang thiếu một cái gì đó. Oh và vì lý do nào đó nó hoạt động khi nút không rỗng.

Dưới đây là trích đoạn mã của tôi.

List<GrantAgresso> lsResult = (from g in xml.Element("root").Elements("Elementname") 
     select new GrantAgresso() 
     { 
      Year = (int?)g.Element("yearnode") ?? 0, 
      Subdomain = (string)g.Element("domainnode") ?? "" 
     }).ToList(); 

Các errormessage là:

Input string was not in a correct format.

Nếu ai có một đầu mối như những gì tôi đang làm sai, xin vui lòng giúp :)

Edit: mảnh XML (tên lạ nhưng đó là chứ không phải bằng sự lựa chọn)

<Agresso> 
    <AgressoQE> 
    <r3dim_value>2012</r3dim_value> 
    <r0r0r0dim_value>L5</r0r0r0dim_value> 
    <r7_x0023_province_x0023_69_x0023_V005>0</r7_x0023_province_x0023_69_x0023_V005> 
    <r7_x0023_postal_code_x0023_68_x0023_V004 /> 
    <r7_x0023_country_x0023_67_x0023_V003>1004</r7_x0023_country_x0023_67_x0023_V003> 
    <r7_x0023_communitydistrict_x0023_70_x0023_V006>0</r7_x0023_communitydistrict_x0023_70_x0023_V006> 
    </AgressoQE> 
</Agresso> 
+1

đặt cược của tôi là về cú pháp xml không chính xác. Bạn có thể hiển thị nội dung xml không? Toán tử kết hợp là đúng và nếu nó không phải là nó sẽ không ném lỗi này (nó không liên quan gì đến chuỗi) –

+0

Bài tập 'Year' hoặc' Subdomain' có ném ngoại lệ không? Bạn có thể thử nhận xét một trong các dòng để xem liệu ngoại lệ có biến mất hay không. – Mizipzor

+0

Tôi đã thêm một nút xml vào bài đăng của mình. Đây là nút trống (bắt đầu bằng r7_) kích hoạt ngoại lệ. Mã tôi đã sử dụng để lấy nó giống như những gì tôi đã sử dụng trong năm. – Nielsm

Trả lời

1

Phương pháp mở rộng sau đây sẽ trở về 0 cả hai nếu nguyên tố này là không có mặt, nguyên tố này là trống hay nó chứa một chuỗi mà không thể được phân tích để nguyên:

public static int ToInt(this XElement x, string name) 
    { 
     int value; 
     XElement e = x.Element(name); 
     if (e == null) 
      return 0; 
     else if (int.TryParse(e.Value, out value)) 
      return value; 
     else return 0; 
    } 

Bạn có thể sử dụng nó như thế này:

... 
Year = g.ToInt("r3dim_value"), 
... 

Hoặc nếu bạn đã sẵn sàng để xem xét chi phí phản ánh và để chấp nhận các giá trị mặc định của bất kỳ loại giá trị, bạn có thể sử dụng phương pháp mở rộng này:

public static T Cast<T>(this XElement x, string name) where T : struct 
{ 
    XElement e = x.Element(name); 
    if (e == null) 
     return default(T); 
    else 
    { 
     Type t = typeof(T); 
     MethodInfo mi = t.GetMethod("TryParse", 
            BindingFlags.Public | BindingFlags.Static, 
            Type.DefaultBinder, 
            new Type[] { typeof(string), 
               t.MakeByRefType() }, 
            null); 
     var paramList = new object[] { e.Value, null }; 
     mi.Invoke(null, paramList); 
     return (T)paramList[1]; //returns default(T), if couldn't parse 
    } 
} 

và sử dụng nó:

... 
Year = g.Cast<int>("r3dim_value"), 
... 
+0

Tôi đã sử dụng đề xuất thứ hai của bạn. Cám ơn! – Nielsm

1

Bạn có thể thêm Where operator

..... 
.Where(a => ! string.IsNullOrEmpty(a)).ToList(); 
+0

'a' được cho là gì? Tại sao bạn gọi 'ToList' trên cái gì trông giống như một 'IEnumerable '? – Rawling

+2

Điều này không làm những gì OP đang cố gắng làm. –

+1

Không, tôi không muốn lọc kết quả, tôi chỉ không muốn chương trình của tôi bị ngắt khi một nút trống xuất hiện ... – Nielsm

1

Nếu năm trống hoặc trống chuỗi mà bạn sẽ nhận được một chuỗi "Nhập liệu không đúng định dạng". Bạn có thể viết một phương thức mở rộng để đọc các giá trị. Tôi đã không kiểm tra mã dưới đây, nhưng nó có thể cung cấp cho bạn một số gợi ý.

public static ReadAs<T>(this XElement el, T defaultValue) { 
    var v = (string)el; // cast string to see if it is empty 

    if (string.IsNullOrEmpty(v)) // test 
    return defaultValue; 

    return (T)el; // recast to our type. 
} 
2

Đó là biểu hiện này được ném:

(int?)g.Element("yearnode") 

Đó là vì nếu giá trị thực tế của nút văn bản của phần tử là String.Empty và không null, kể từ khi chuỗi rỗng không phải là một định dạng hợp lệ cho Int32.Parse , dàn diễn viên đã thất bại.

Nếu phần tử bị thiếu hoàn toàn khỏi XML của bạn, điều này hoạt động như bạn mong đợi, nhưng nếu có thẻ trống <yearnode/> hoặc <yearnode></yearnode>, bạn sẽ nhận được ngoại lệ.

+0

Đây có thể là câu trả lời tôi đang tìm kiếm. Những gì bạn sẽ đề nghị tôi làm gì? – Nielsm

1

Thông báo Input string was not in a correct format trông giống như hình được ném bởi int.parse() để có thể là bạn có yearnode có giá trị (không phải là null) nhưng không thể phân tích thành công thành giá trị nguyên.

Something như thế này có thể khắc phục nó:

List<GrantAgresso> lsResult = (from g in xml.Element("root").Elements("Elementname") 
    let yearNode = g.Element("yearnode") 
    select new GrantAgresso 
    { 
     Year = string.IsNullOrWhiteSpace(yearNode.Value) ? 0 : int.Parse(yearNode.Value), 
     Subdomain = g.Element("domainnode").Value 
    }).ToList(); 

Một vài điều cần lưu ý:

select new GrantAgresso - bạn không cần ngoặc cho một constructor mặc định với initializers đối tượng.

string.IsNullOrWhiteSpace - được giới thiệu trong .net 4.0, sử dụng string.IsNullOrEmpty nếu bạn đang sử dụng 3.5 hoặc sớm hơn

g.Element("domainnode").Value - sẽ luôn luôn trả về một chuỗi

nếu bạn muốn có một null cho năm thay vì 0, sử dụng (int?)null thay vì 0

+0

Xin chào, Tôi vừa kiểm tra gấp đôi & gấp ba lần XML của mình, các giá trị tôi muốn chuyển đổi thành int hoặc là rỗng hoặc một số nguyên hợp lệ. Đây là điều tôi cũng đã xem xét ;-) – Nielsm

+0

Tôi đã cập nhật câu trả lời của mình với đề xuất để xử lý các ô trống. –

0

Vấn đề của bạn là rằng các diễn viên từ XElement để int? sử dụng phương thức int.Parse trên giá trị chuỗi của XElement, trong trường hợp của bạn là String.Empty. Các kết quả sau trong cùng một lỗi:

XElement x = new XElement("yearnode", String.Empty); 
int? a = (int?)x; // throws FormatException 

Bạn có thể tránh điều này bằng cách đầu tiên đưa XElement vào chuỗi và kiểm tra xem nó có rỗng hoặc trống và chỉ khi không thực hiện truyền tới int ?. Để làm điều này, hãy thay

Year = (int?)g.Element("yearnode") ?? 0, 

với

Year = !string.IsNullOrEmpty((string)g.Element("yearnode")) ? (int?)g.Element("yearnode") : 0, 

của nó không đẹp và vẫn sẽ ném nếu chuỗi là bằng cách khác không hợp pháp, nhưng nó hoạt động nếu bạn có thể giả định rằng nguyên tố này luôn luôn là một số nguyên hoặc null/trống.

Các vấn đề liên quan