2010-03-30 32 views
9

Đây là lớp học của tôi:Làm thế nào để deserialize null mảng để null trong C#?

public class Command 
{ 
    [XmlArray(IsNullable = true)] 
    public List<Parameter> To { get; set; } 
} 

Khi tôi serialize một đối tượng của lớp này:

var s = new XmlSerializer(typeof(Command)); 
s.Serialize(Console.Out, new Command()); 

nó in như mong đợi (tiêu đề xml và mặc định MS không gian tên được bỏ qua):

<Command><To xsi:nil="true" /></Command> 

Khi tôi lấy xml này và cố gắng deserialize nó tôi đã bị mắc kẹt, bởi vì nó luôn luôn in "Không null":

var t = s.Deserialize(...); 
if (t.To == null) 
    Console.WriteLine("Null"); 
else 
    Console.WriteLine("Not null"); 

Làm thế nào để buộc deserializer làm cho danh sách của tôi rỗng, nếu nó là null trong xml?

+0

Là nó thực sự quan trọng đối với bạn nếu bạn không có danh sách hoặc một danh sách trống? –

+0

Đúng. Tôi có thể giải quyết trường hợp này với một số lá cờ tất nhiên, nhưng tôi muốn biết nếu có một giải pháp tiêu chuẩn tốt. –

+1

Tránh các đối tượng null thường là một điều tốt (ít bị lỗi, không cần phải kiểm tra null tất cả xung quanh mã vv). Sử dụng cờ sẽ chỉ rõ chính xác giá trị null đó đại diện cho cái gì. – Groo

Trả lời

2

Ugh, gây phiền nhiễu không phải là nó. Bạn có thể thấy nó đang làm bằng cách chạy sgen.exe trên assembly của bạn với các tùy chọn/keep và/debug để bạn có thể gỡ lỗi mã deserialization. Nó trông gần giống như thế này:

global::Command o; 
o = new global::Command(); 
if ((object)([email protected]) == null) [email protected] = new global::System.Collections.Generic.List<global::Parameter>(); 
global::System.Collections.Generic.List<global::Parameter> a_0 = (global::System.Collections.Generic.List<global::Parameter>)[email protected]; 
// code elided 
//... 
while (Reader.NodeType != System.Xml.XmlNodeType.EndElement && Reader.NodeType != System.Xml.XmlNodeType.None) { 
    if (Reader.NodeType == System.Xml.XmlNodeType.Element) { 
    if (((object)Reader.LocalName == (object)id4_To && (object)Reader.NamespaceURI == (object)id2_Item)) { 
     if (!ReadNull()) { 
     if ((object)([email protected]) == null) [email protected] = new global::System.Collections.Generic.List<global::Parameter>(); 
     global::System.Collections.Generic.List<global::Parameter> a_0_0 = (global::System.Collections.Generic.List<global::Parameter>)[email protected]; 
     // code elided 
     //... 
     } 
     else { 
     // Problem here: 
     if ((object)([email protected]) == null) [email protected] = new global::System.Collections.Generic.List<global::Parameter>(); 
     global::System.Collections.Generic.List<global::Parameter> a_0_0 = (global::System.Collections.Generic.List<global::Parameter>)[email protected]; 
     } 
    } 
    } 
    Reader.MoveToContent(); 
    CheckReaderCount(ref whileIterations1, ref readerCount1); 
} 
ReadEndElement(); 
return o; 

Không ít hơn 3 nơi đảm bảo thuộc tính @To không rỗng. Việc đầu tiên là phần nào có khả năng bảo vệ, khó phân giải dữ liệu khi cấu trúc không tồn tại. Điều thứ hai thực hiện kiểm tra null một lần nữa, đó là điều thực sự tốt nhất. Thứ ba là vấn đề, ReadNull() trả về true nhưng nó vẫn còn tạo ra một giá trị thuộc tính không null.

Nếu bạn muốn phân biệt giữa rỗng và rỗng thì bạn không có giải pháp tốt nhưng chỉnh sửa mã này bằng tay. Thực hiện điều này chỉ nếu bạn thực sự tuyệt vọng và lớp học ổn định 100%. Chà, đừng làm thế. Giải pháp của João là giải pháp tốt nhất.

+0

Cảm ơn. Tôi sẽ thêm cờ. –

0

Tôi đồng ý với nhận xét của @ Oliver, nhưng bạn có thể giải quyết nó như thế này nếu bạn thực sự cần nó để trả về giá trị rỗng. Thay vì sử dụng thuộc tính tự động, hãy tạo trường sao lưu của riêng bạn.

List<Parameter> _to; 
public List<Parameter> To 
{ 
    get 
    { 
     if (_to != null && _to.Count == 0) return null; 
     return _to; 
    } 
    set { _to = value; } 
} 
+0

Tôi tin rằng OP muốn * phân biệt * danh sách trống và trống. – Groo

+0

Thật không may, trong trường hợp của tôi, danh sách trống và danh sách rỗng là khác nhau. –

+0

Điều đó khiến cho việc này trở nên phức tạp hơn ngay lập tức: ( –

0

Nếu bạn thực sự cần là một bộ sưu tập được deserialized để null khi không có giá trị được cung cấp bạn có thể làm điều đó bằng cách không cung cấp một accessor set, như thế này:

public class Command 
{ 
    private List<Parameter> to; 

    public List<Parameter> To { get { return this.to; } } 
} 
+0

Lựa chọn không hợp lệ. "Tới" sẽ luôn luôn rỗng sau khi hủy tham chiếu. –

3

Nếu bạn sử dụng một mảng thay vì một danh sách nó hoạt động như mong đợi

public class Command 
{ 
    [XmlArray(IsNullable = true)] 
    public Parameter[] To { get; set; } 
} 
Các vấn đề liên quan