it-swarm-vi.tech

.NET XML tuần tự hóa gotchas?

Tôi đã gặp một vài vấn đề khi thực hiện tuần tự hóa C # XML mà tôi nghĩ tôi muốn chia sẻ:


using System;
using System.Collections.Generic;
using System.Text;
using System.Xml.Serialization;

[XmlRoot("dictionary")]
public class SerializableDictionary<TKey, TValue> : Dictionary<TKey, TValue>, IXmlSerializable
{      
    public System.Xml.Schema.XmlSchema GetSchema()
    {
        return null;
    }

    public void ReadXml(System.Xml.XmlReader reader)
    {
        XmlSerializer keySerializer = new XmlSerializer(typeof(TKey));
        XmlSerializer valueSerializer = new XmlSerializer(typeof(TValue));

        bool wasEmpty = reader.IsEmptyElement;
        reader.Read();

        if (wasEmpty)
            return;

        while (reader.NodeType != System.Xml.XmlNodeType.EndElement)
        {
            reader.ReadStartElement("item");

            reader.ReadStartElement("key");
            TKey key = (TKey)keySerializer.Deserialize(reader);
            reader.ReadEndElement();

            reader.ReadStartElement("value");
            TValue value = (TValue)valueSerializer.Deserialize(reader);
            reader.ReadEndElement();

            this.Add(key, value);

            reader.ReadEndElement();
            reader.MoveToContent();
        }
        reader.ReadEndElement();
    }

    public void WriteXml(System.Xml.XmlWriter writer)
    {
        XmlSerializer keySerializer = new XmlSerializer(typeof(TKey));
        XmlSerializer valueSerializer = new XmlSerializer(typeof(TValue));

        foreach (TKey key in this.Keys)
        {
            writer.WriteStartElement("item");

            writer.WriteStartElement("key");
            keySerializer.Serialize(writer, key);
            writer.WriteEndElement();

            writer.WriteStartElement("value");
            TValue value = this[key];
            valueSerializer.Serialize(writer, value);
            writer.WriteEndElement();

            writer.WriteEndElement();
        }
    }
}

Có bất kỳ vấn đề tuần tự hóa XML nào khác không?

120
Kalid

Một vấn đề lớn khác: khi xuất XML thông qua một trang web (ASP.NET), bạn không muốn bao gồm nicode Byte-Order Mark . Tất nhiên, các cách sử dụng hay không sử dụng BOM gần như giống nhau:

BAD (bao gồm BOM):

XmlTextWriter wr = new XmlTextWriter(stream, new System.Text.Encoding.UTF8);

TỐT:

XmlTextWriter  wr = new XmlTextWriter(stream, new System.Text.UTF8Encoding(false))

Bạn rõ ràng có thể chuyển sai để cho biết bạn không muốn BOM. Lưu ý sự khác biệt rõ ràng, rõ ràng giữa Encoding.UTF8UTF8Encoding.

Ba byte BOM bổ sung ở đầu là (0xEFBBBF) hoặc (239 187 191).

Tham khảo: http://chrislaco.com/blog/troubledhoot-common-probols-with-the-xmlserializer/

27
Kalid

Tôi chưa thể đưa ra nhận xét nào, vì vậy tôi sẽ nhận xét về bài đăng của Dr8k và thực hiện một quan sát khác. Các biến riêng được hiển thị dưới dạng các thuộc tính getter/setter công khai và được tuần tự hóa/giải tuần tự như vậy thông qua các thuộc tính đó. Chúng tôi đã làm điều đó tại công việc cũ của tôi al.

Mặc dù vậy, một điều cần lưu ý là nếu bạn có bất kỳ logic nào trong các thuộc tính đó, logic sẽ được chạy, vì vậy đôi khi, thứ tự tuần tự hóa thực sự có vấn đề. Các thành viên là ngầm được sắp xếp theo cách họ được sắp xếp trong mã, nhưng không có gì đảm bảo, đặc biệt là khi bạn đang kế thừa một đối tượng khác. Rõ ràng ra lệnh cho họ là một nỗi đau ở phía sau.

Tôi đã bị cháy bởi điều này trong quá khứ.

21
Charles Graham

Khi tuần tự hóa thành chuỗi XML từ luồng bộ nhớ, hãy chắc chắn sử dụng MemoryStream # ToArray () thay vì MemoryStream # GetBuffer () hoặc bạn sẽ kết thúc với các ký tự rác không được khử lưu chính xác (vì bộ đệm bổ sung được phân bổ).

http://msdn.Microsoft.com/en-us/l Library/system.io.memorystream.getbuffer (VS.80) .aspx

15
realgt

IEnumerables<T> được tạo thông qua lợi nhuận không được tuần tự hóa. Điều này là do trình biên dịch tạo ra một lớp riêng biệt để thực hiện trả về lợi tức và lớp đó không được đánh dấu là tuần tự hóa.

10
bwillard

Nếu serializer gặp một thành viên/thuộc tính có giao diện như kiểu của nó, nó sẽ không serialization. Ví dụ: sau đây sẽ không tuần tự hóa thành XML:

public class ValuePair
{
    public ICompareable Value1 { get; set; }
    public ICompareable Value2 { get; set; }
}

Mặc dù điều này sẽ tuần tự hóa:

public class ValuePair
{
    public object Value1 { get; set; }
    public object Value2 { get; set; }
}
10
Allon Guralnek

Bạn không thể tuần tự hóa các thuộc tính chỉ đọc. Bạn phải có một getter và setter, ngay cả khi bạn không bao giờ có ý định sử dụng giải tuần tự hóa để biến XML thành một đối tượng.

Vì lý do tương tự, bạn không thể tuần tự hóa các thuộc tính trả về giao diện: trình giải mã sẽ không biết lớp cụ thể nào để khởi tạo.

8
Tim Robinson

Đây là một điều tốt: vì mã tuần tự hóa XML được tạo và được đặt trong một DLL riêng biệt, bạn không gặp phải bất kỳ lỗi có ý nghĩa nào khi có lỗi trong mã của bạn phá vỡ trình tuần tự hóa. Chỉ cần một cái gì đó như "không thể xác định vị trí s3d3fsdf.dll". Đẹp.

7
Eric Z Beard

Không thể tuần tự hóa một đối tượng không có cấu hình không tham số (vừa bị đối tượng đó cắn).

Và vì một số lý do, từ các thuộc tính sau, Giá trị được tuần tự hóa, nhưng không phải là FullName:

    public string FullName { get; set; }
    public double Value { get; set; }

Tôi chưa bao giờ tìm ra lý do tại sao, tôi chỉ thay đổi Giá trị thành nội bộ ...

6
Benjol

Một điều nữa cần lưu ý: bạn không thể tuần tự hóa các thành viên lớp riêng tư/được bảo vệ nếu bạn đang sử dụng tuần tự hóa XML "mặc định".

Nhưng bạn có thể chỉ định logic tuần tự hóa XML tùy chỉnh triển khai IXmlSerializable trong lớp của bạn và tuần tự hóa bất kỳ trường riêng nào bạn cần/muốn.

http://msdn.Microsoft.com/en-us/l Library/system.xml.serialization.ixmlserializable.aspx

5
Max Galkin

Bạn có thể phải đối mặt với các vấn đề nối tiếp các đối tượng thuộc loại Màu và/hoặc Phông chữ.

Đây là những lời khuyên, đã giúp tôi:

http://www.codeproject.com/KB/XML/xmlsinstall.aspx

http://www.codeproject.com/KB/cs/GenericXmlSerializition.aspx

4
Max Galkin

Xem " Hỗ trợ liên kết ngôn ngữ định nghĩa lược đồ XML nâng cao " để biết chi tiết về những gì được Trình tuần tự XML hỗ trợ và để biết chi tiết về cách hỗ trợ các tính năng XSD được hỗ trợ.

4
John Saunders

Nếu bạn cố gắng tuần tự hóa một mảng, List<T> Hoặc IEnumerable<T> Chứa các trường hợp của các lớp con của T, bạn cần sử dụng XmlArrayItemAttribution để liệt kê tất cả các kiểu con đang được sử dụng. Nếu không, bạn sẽ nhận được System.InvalidOperationException Không hữu ích khi chạy khi bạn tuần tự hóa.

Đây là một phần của một ví dụ đầy đủ từ tài liệ

public class Group
{  
   /* The XmlArrayItemAttribute allows the XmlSerializer to insert both the base 
      type (Employee) and derived type (Manager) into serialized arrays. */

   [XmlArrayItem(typeof(Manager)), XmlArrayItem(typeof(Employee))]
   public Employee[] Employees;
4
MarkJ

Nếu Hội đồng được tạo tuần tự hóa XML của bạn không nằm trong cùng bối cảnh Tải như mã đang cố sử dụng nó, bạn sẽ gặp phải các lỗi tuyệt vời như:

System.InvalidOperationException: There was an error generating the XML document.
---System.InvalidCastException: Unable to cast object
of type 'MyNamespace.Settings' to type 'MyNamespace.Settings'. at
Microsoft.Xml.Serialization.GeneratedAssembly.
  XmlSerializationWriterSettings.Write3_Settings(Object o)

Nguyên nhân của việc này đối với tôi là một plugin được tải bằng cách sử dụng LoadFrom bối cảnh có nhiều nhược điểm khi sử dụng bối cảnh Load. Một chút thú vị theo dõi mà xuống.

4
user7116

Các thuộc tính được đánh dấu bằng thuộc tính Obsolete không được tuần tự hóa. Tôi chưa thử nghiệm với thuộc tính Deprecated nhưng tôi cho rằng nó sẽ hoạt động theo cùng một cách.

3
James Hulse

Các biến/thuộc tính riêng tư không được tuần tự hóa trong cơ chế mặc định cho tuần tự hóa XML, nhưng ở dạng tuần tự nhị phân.

3
Charles Graham

Nếu XSD của bạn sử dụng các nhóm thay thế, thì rất có thể bạn không thể (hủy) tuần tự hóa nó. Bạn sẽ cần phải viết serial serial của riêng bạn để xử lý tình huống này.

Ví dụ.

<xs:complexType name="MessageType" abstract="true">
    <xs:attributeGroup ref="commonMessageAttributes"/>
</xs:complexType>

<xs:element name="Message" type="MessageType"/>

<xs:element name="Envelope">
    <xs:complexType mixed="false">
        <xs:complexContent mixed="false">
            <xs:element ref="Message" minOccurs="0" maxOccurs="unbounded"/>
        </xs:complexContent>
    </xs:complexType>
</xs:element>

<xs:element name="ExampleMessageA" substitutionGroup="Message">
    <xs:complexType mixed="false">
        <xs:complexContent mixed="false">
                <xs:attribute name="messageCode"/>
        </xs:complexContent>
    </xs:complexType>
</xs:element>

<xs:element name="ExampleMessageB" substitutionGroup="Message">
    <xs:complexType mixed="false">
        <xs:complexContent mixed="false">
                <xs:attribute name="messageCode"/>
        </xs:complexContent>
    </xs:complexType>
</xs:element>

Trong ví dụ này, một Phong bì có thể chứa Tin nhắn. Tuy nhiên, trình tuần tự mặc định của .NET không phân biệt giữa Message, exampleMessageA và exampleMessageB. Nó sẽ chỉ tuần tự hóa đến và từ lớp Message cơ sở.

2
ilitirit

Hãy cẩn thận các kiểu tuần tự hóa mà không có tuần tự hóa rõ ràng, nó có thể dẫn đến sự chậm trễ trong khi .Net xây dựng chúng. Tôi đã phát hiện ra điều này gần đây trong khi xê-ri hóa RSAParameter .

2
Keith

Tôi thực sự không thể giải thích điều này, nhưng tôi thấy điều này sẽ không nối tiếp:

[XmlElement("item")]
public myClass[] item
{
    get { return this.privateList.ToArray(); }
}

nhưng điều này sẽ:

[XmlElement("item")]
public List<myClass> item
{
    get { return this.privateList; }
}

Và cũng đáng lưu ý rằng nếu bạn đăng tuần tự lên một bản ghi nhớ, bạn có thể muốn tìm đến 0 trước khi sử dụng nó.

2
annakata

Các biến/thuộc tính riêng tư không được tuần tự hóa trong tuần tự hóa XML, nhưng là trong tuần tự hóa nhị phân.

Tôi tin rằng điều này cũng có được bạn nếu bạn tiếp xúc với các thành viên tư nhân thông qua các tài sản công cộng - các thành viên tư nhân không được đăng tuần tự để các thành viên công cộng đều tham chiếu các giá trị null.

0
Dr8k