2009-03-31 26 views
25

Giả sử tôi có đối tượng này:Làm thế nào để tạo một kiểu giá trị rỗng với .NET XmlSerializer?

[Serializable] 
public class MyClass 
{ 
    public int Age { get; set; } 
    public int MyClassB { get; set; } 
} 
[Serializable] 
public class MyClassB 
{ 
    public int RandomNumber { get; set; } 
} 

XmlSerializer sẽ serialize các đối tượng như thế:

<MyClass> 
    <Age>0</age> 
    <MyClassB> 
     <RandomNumber>4234</RandomNumber> 
    </MyClassB> 
</MyClass> 

Làm thế nào tôi có thể làm cho Tuổi nullable bất động sản? IE: không tuần tự hóa thuộc tính Tuổi khi nó dưới 0?

Tôi đã thử với Nullable, nhưng nó serialize đối tượng của tôi như thế:

<MyClass> 
    <Age d5p1:nil="true" /> 
    <MyClassB> 
     <RandomNumber>4234</RandomNumber> 
    </MyClassB> 
</MyClass>  

Bằng cách đọc các tài liệu MSDN Tôi thấy điều này:

Bạn không thể áp dụng các tài sản IsNullable cho một thành viên đánh máy như một kiểu giá trị vì một kiểu giá trị không thể chứa tham chiếu nullNothingnullptra null (Không có gì trong Visual Basic). Ngoài ra, bạn không thể đặt thuộc tính này thành false cho các loại giá trị rỗng. Khi các kiểu như vậy là tham chiếu nullNothingnullptra null (Không có gì trong Visual Basic), chúng sẽ được tuần tự hóa bằng cách thiết lập xsi: nil thành true.

nguồn: http://msdn.microsoft.com/en-us/library/system.xml.serialization.xmlelementattribute.isnullable.aspx

Tôi hiểu một loại giá trị không thể được thiết lập để null. Một valuetype luôn luôn được thiết lập để một cái gì đó. Việc serialization không thể đưa ra quyết định serialize nó hay không dựa trên giá trị hiện tại của nó.

Tôi đã thử với các thuộc tính, nhưng nó không hoạt động. Tôi đã cố gắng tạo ra một đối tượng agecontainer và thao tác nó serialization với các thuộc tính, nhưng nó đã không làm việc ra ngoài.

Những gì tôi thực sự muốn là:

<MyClass> 
    <MyClassB> 
     <RandomNumber>4234</RandomNumber> 
    </MyClassB> 
</MyClass> 

Khi Tuổi tài sản là dưới 0 (zero).


Có vẻ như bạn sẽ phải triển khai tùy chỉnh tuần tự hóa.

Vâng, đó là những gì tôi mặc dù quá, nhưng tôi muốn tránh xa mà không có nó.

Trong ứng dụng, đối tượng phức tạp hơn nhiều và tôi không muốn xử lý tuần tự.

Trả lời

49

Tôi vừa phát hiện ra điều này. XmlSerialier tìm kiếm thuộc tính boolean XXXSpecified để xác định xem nó có được bao gồm hay không. Điều này sẽ giải quyết vấn đề một cách độc đáo.

[Serializable] 
public class MyClass 
{ 
    public int Age { get; set; } 
    [XmlIgnore] 
    public bool AgeSpecified { get { return Age >= 0; } } 
    public int MyClassB { get; set; } 
} 

[Serializable] 
public class MyClassB 
{ 
    public int RandomNumber { get; set; } 
} 

Proof:

static string Serialize<T>(T obj) 
{ 
    var serializer = new XmlSerializer(typeof(T)); 
    var builder = new StringBuilder(); 
    using (var writer = new StringWriter(builder)) 
    { 
    serializer.Serialize(writer, obj); 
    return builder.ToString(); 
    } 
} 

static void Main(string[] args) 
{ 
    var withoutAge = new MyClass() { Age = -1 }; 
    var withAge = new MyClass() { Age = 20 }; 

    Serialize(withoutAge); // = <MyClass><MyClassB>0</MyClassB></MyClass> 
    Serialize(withAge); // = <MyClass><Age>20</Age><MyClassB>0</MyClassB></MyClass> 
} 

Sửa: Vâng, đó là một tính năng ghi chép lại.Xem MSDN entry for XmlSerializer

Một tùy chọn khác là sử dụng mẫu đặc biệt để tạo trường Boolean được XmlSerializer nhận dạng và áp dụng XmlIgnoreAttribute cho trường này. Mẫu được tạo dưới dạng propertyNameSpecified. Ví dụ, nếu có một trường có tên là "MyFirstName", bạn cũng sẽ tạo một trường có tên "MyFirstNameSpecified" chỉ thị cho XmlSerializer liệu có tạo phần tử XML có tên là "MyFirstName" hay không.

+1

+1 đó là mẹo nhỏ gọn! Bạn có biết nếu đó là một tính năng không có giấy tờ hoặc nếu nó được hỗ trợ đầy đủ? – James

+0

@James đã ở đó trước khi có thể vô hiệu hóa, vì vậy nó sẽ hoạt động tốt :) Tôi đã sử dụng nó một thời gian trước đây và không gặp phải bất kỳ sự cố nào. – eglasius

+0

Nhưng nó là một tài liệu (và do đó, hỗ trợ) tính năng? –

2

Điều này sẽ giúp Làm cho độ tuổi? và ..

public bool ShouldSerializeAge() { return Age.HasValue; } 

..nó có nghĩa là thêm phương pháp ShouldSerializeXXX vào lớp học của bạn!

+0

Ngoài ra, theo tài liệu MSDN, chúng ta nên thực hiện phương thức resetXXX, nó sẽ chỉ đặt lại thành null. Hai phương pháp xuất hiện để làm việc cùng nhau. –

0

Quên về Nullable ... ShouldSerializeXXX là một giải pháp khá. Ở đây Tuổi sẽ được sắp xếp theo tình trạng của bạn.

[Serializable] 
public class MyClass 
{ 
    public int Age { get; set; } 
    public int MyClassB { get; set; } 

    #region Conditional Serialization 
    public bool ShouldSerializeAge() { return age > 0; } 
    #endregion 
} 

[Serializable] 
public class MyClassB 
{ 
    public int RandomNumber { get; set; } 
} 
13

Mở rộng câu trả lời Samuel và bình luận Greg Beech để trường hợp một tài sản boolean: nếu tài sản là kiểu bool sau đó bạn không thể viết một bài kiểm tra đơn giản trong tài sản propertySpecified.

Giải pháp là sử dụng loại Nullable <bool>, sau đó kiểm tra trong thuộc tính Thuộc tính được xác định đơn giản là thuộc tính.HasValue. ví dụ.

using System.Xml.Serialization; 

public class Person 
{ 
    public bool? Employed { get; set; } 

    [XmlIgnore] 
    public bool EmployedSpecified { get { return Employed.HasValue; } } 
} 

Một thay thế cho việc sử dụng một loại nullable cho một tài sản số (được đề xuất bởi Greg Beech) là để thiết lập thuộc tính giá trị cho một giá trị mặc định không hợp lệ, chẳng hạn như -1, như sau:

using System.ComponentModel; 
using System.Xml.Serialization; 

public class Person 
{ 
    [DefaultValue(-1)] 
    public int Age { get; set; } 

    [XmlIgnore] 
    public bool AgeSpecified { get { return Age >= 0; } } 
} 
0

xsd.exe sẽ tự động tạo thuộc tính XXXSpecified và accessors nếu bạn đặt thuộc tính 'minoccurs' là 'minoccurs = "0"' cho một phần tử ... nếu bạn đang sử dụng lược đồ để xác định xml/class

+0

-1: cảm ơn vì đã cố gắng trả lời câu hỏi, nhưng rõ ràng từ câu hỏi mà OP bắt đầu với các đối tượng chứ không phải lược đồ. –

+0

Nó thực sự rất hữu ích cho tôi, cảm ơn – Guillaume86

4

Bạn có thể sử dụng XmlElementAttribute.IsNullable :

[Serializable] 
public class MyClass 
{ 
    [XmlElement(IsNullable = true)] 
    public int? Age { get; set; } 

    public int MyClassB { get; set; } 
} 
Các vấn đề liên quan