.NET XML serileştirme sorunları var mı? [kapalı]


121

C # XML serileştirme yaparken paylaşacağımı düşündüğüm birkaç sorunla karşılaştım:


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();
        }
    }
}

Orada başka XML Serileştirme var mı?


Daha fazla gotchas lol
arıyor,

1
Ayrıca, Charles Feduke'un serileştirilebilir sözlük uygulamasına bir göz atmak isteyeceksiniz, xml yazarının, varsayılan serileştirici tarafından serileştirilecek normal üyelere atfedilebilir üyeler arasında fark etmesini sağladı: deploymentzone.com/2008/09/19/…
Shimmy Weitzhandler

Bu, tüm sorunları yakalayabilecek gibi görünmüyor. Yapıcıda IEqualityComparer ayarlıyorum, ancak bu, bu kodda serileştirilmiyor. Bu sözlüğün bu bilgiyi içerecek şekilde nasıl genişletileceğine dair bir fikriniz var mı? bu bilgi Type nesnesi aracılığıyla işlenebilir mi?
ColinCren

Yanıtlar:


27

Başka bir büyük sorun: XML'yi bir web sayfası (ASP.NET) üzerinden çıkarırken, Unicode Bayt Sırası İşaretini dahil etmek istemezsiniz . Elbette, ürün reçetesini kullanma veya kullanmama yolları hemen hemen aynıdır:

KÖTÜ (ürün reçetesini içerir):

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

İYİ:

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

Malzeme Listesini istemediğinizi belirtmek için açıkça false değerini iletebilirsiniz. Arasında net, bariz farklara dikkat edin Encoding.UTF8ve UTF8Encoding.

Başlangıçta fazladan üç BOM Baytı (0xEFBBBF) veya (239 187 191).

Referans: http://chrislaco.com/blog/trfunction-common-problems-with-the-xmlserializer/


4
Bize ne olduğunu değil, nedenini de söylerseniz yorumunuz daha da faydalı olacaktır.
Neil

1
Bu gerçekten XML serileştirmeyle ilgili değil ... bu sadece bir XmlTextWriter sorunu
Thomas Levesque

7
-1: Soruyla ilgili değil XmlTextWriterve .NET 2.0 veya üstünde kullanmamalısınız.
John Saunders

Çok yararlı referans bağlantısı. Teşekkürler.
Anil Vangari

21

Henüz yorum yapamıyorum, bu yüzden Dr8k'in gönderisine yorum yapıp başka bir gözlem yapacağım. Genel alıcı / ayarlayıcı özellikleri olarak açığa çıkan ve bu özellikler aracılığıyla bu şekilde serileştirilen / seri kaldırılan özel değişkenler. Bunu her zaman eski işimde yaptık.

Bununla birlikte, bu özelliklerde herhangi bir mantığınız varsa, mantık çalıştırılır, bu nedenle bazen serileştirme sırası gerçekten önemlidir. Üyeler, kodda nasıl sıralandıklarına göre dolaylı olarak sıralanır, ancak özellikle başka bir nesneyi devralırken hiçbir garanti yoktur. Onları açıkça sipariş etmek arka tarafta bir acıdır.

Geçmişte bununla yanmıştım.


17
Bu gönderiyi, alanların sırasını açıkça belirlemenin yollarını ararken buldum. Bu, özniteliklerle yapılır: [XmlElementAttribute (Order = 1)] public int Field {...} Olumsuz tarafı: öznitelik, sınıftaki TÜM alanlar ve tüm alt öğeleri için belirtilmelidir! IMO Bunu mesajınıza eklemelisiniz.
Cristian Diaconescu

15

Bir bellek akışından bir XML dizesine serileştirirken, MemoryStream # GetBuffer () yerine MemoryStream # ToArray () kullandığınızdan emin olun, aksi takdirde doğru şekilde seriyi kaldırmayan önemsiz karakterler elde edersiniz (ayrılan fazladan tampon nedeniyle).

http://msdn.microsoft.com/en-us/library/system.io.memorystream.getbuffer(VS.80).aspx


3
doğrudan dokümandan "Arabelleğin kullanılmamış olabilecek tahsis edilmiş baytlar içerdiğine dikkat edin. Örneğin," test "dizesi MemoryStream nesnesine yazılırsa, GetBuffer'dan döndürülen arabelleğin uzunluğu 4 değil 256'dır, 252 bayt kullanılmıyor. Yalnızca arabellekteki verileri elde etmek için ToArray yöntemini kullanın; ancak ToArray, bellekteki verilerin bir kopyasını oluşturur. " msdn.microsoft.com/en-us/library/…
realgt

sadece şimdi bunu gördüm. Artık kulağa saçma gibi gelmiyor.
John Saunders

Bunu daha önce hiç duymadım, bu da hata ayıklamaya yardımcı olur.
Ricky

10

Serileştirici, türü arabirim olan bir üye / özellik ile karşılaşırsa, serileştirmez. Örneğin, aşağıdakiler XML olarak serileştirilmez:

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

Bu serileştirecek olsa da:

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

"Üye için tür çözülmedi ..." mesajıyla bir istisna alırsanız, olan şey bu olabilir.
Kyle Krull

9

IEnumerables<T>getiri iadeleri yoluyla üretilenler serileştirilemez. Bunun nedeni, derleyicinin getiri dönüşünü uygulamak için ayrı bir sınıf oluşturması ve bu sınıfın serileştirilebilir olarak işaretlenmemesidir.


Bu, "diğer" serileştirme, yani [Serializable] özelliği için geçerlidir. Bu, XmlSerializer için de çalışmıyor.
Tim Robinson


8

Salt okunur özellikleri seri hale getiremezsiniz. XML'i bir nesneye dönüştürmek için seriyi kaldırmayı asla kullanmayı düşünmeseniz bile, bir alıcı ve ayarlayıcıya sahip olmanız gerekir.

Aynı nedenle, arabirimleri döndüren özellikleri serileştiremezsiniz: seriyi kaldıran, hangi somut sınıfın başlatılacağını bilemez.


1
Aslında bir koleksiyon özelliğini, ayarlayıcısı olmasa bile serileştirebilirsiniz, ancak seriyi kaldırma işleminin ona öğeler ekleyebilmesi için yapıcıda başlatılması gerekir
Thomas Levesque

7

İşte iyi bir tane: XML serileştirme kodu oluşturulup ayrı bir DLL'ye yerleştirildiğinden, kodunuzda serileştiriciyi bozan bir hata olduğunda anlamlı bir hata almazsınız. "S3d3fsdf.dll bulunamadı" gibi bir şey. Güzel.


11
XML "Serializer Generator Tool (Sgen.exe)" kullanarak bu DLL'yi önceden oluşturabilir ve uygulamanızla birlikte dağıtabilirsiniz.
huseyint

6

Parametresiz bir kurucuya sahip olmayan bir nesneyi seri hale getiremezsiniz (sadece o tarafından ısırıldı).

Ve bazı nedenlerden dolayı, aşağıdaki özelliklerden, Değer serileştirilir, ancak Tam Ad değil:

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

Nedenini çözemedim, sadece Değeri dahili olarak değiştirdim ...


4
Parametresiz kurucu özel / korumalı olabilir. XML serileştirici için yeterli olacaktır. FullName ile ilgili sorun gerçekten tuhaf, olmamalı ...
Max Galkin

@Yacoder: Belki çünkü değil double?ama sadece double?
abatishchev

FullName büyük olasılıkla idi nullve bu nedenle serileştirildiğinde herhangi bir XML oluşturmayacak
Jesper


4

XML Serileştirme tarafından oluşturulan derlemeniz, onu kullanmaya çalışan kodla aynı Yük bağlamında değilse, aşağıdaki gibi harika hatalarla karşılaşacaksınız:

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)

Bunun benim için nedeni LoadFrom bağlamı kullanılarak yüklenen ve Load bağlamını kullanmanın birçok dezavantajı olan bir eklentiydi . Onu takip etmek oldukça eğlenceli.




4

Eğer, bir dizi seri çalışırsanız List<T>veya IEnumerable<T>örneklerini içeren alt sınıflarının arasında T, kullanmak gerekir XmlArrayItemAttribute listesine tüm alt tipleri kullanılıyor. Aksi takdirde yararsızdırSystem.InvalidOperationException , serileştirdiğinizde çalışma zamanında .

İşte dokümantasyondan tam bir örneğin parçası

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;

3

Özel değişkenler / özellikler, XML serileştirme için varsayılan mekanizmada serileştirilmez, ancak ikili serileştirme içindedir.


2
Evet, "varsayılan" XML serileştirmeyi kullanıyorsanız. Sınıfınızda IXmlSerializable uygulayan özel XML serileştirme mantığı belirtebilir ve ihtiyacınız olan / istediğiniz özel alanları serileştirebilirsiniz.
Max Galkin

1
Bu doğru. Bunu düzelteceğim. Ama bu arayüzü uygulamak, hatırladığım kadarıyla baş belası.
Charles Graham

3

ObsoleteÖznitelikle işaretlenen özellikler serileştirilmez. DeprecatedÖzniteliği test etmedim ama aynı şekilde davranacağını varsayıyorum.


2

Bunu gerçekten açıklayamam ama bunun serileştirilmeyeceğini öğrendim:

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

ama bu:

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

Ayrıca, bir memstream'de seri oluşturuyorsanız, kullanmadan önce 0'ı aramak isteyebileceğinizi de belirtmek gerekir.


Sanırım yeniden inşa edemediği için. İkinci örnekte, Listeye öğe eklemek için item.Add () öğesini çağırabilir. İlk seferde yapamaz.
ilitirit

18
Kullan: [XmlArray ("item"), XmlArrayItem ("myClass", typeof (myClass))]
RvdK,

1
bunun için şerefe! her gün bir şeyler öğren
annakata


2

XSD'niz ikame gruplarını kullanırsa, büyük olasılıkla onu otomatik olarak serileştiremezsiniz (de). Bu senaryoyu işlemek için kendi serileştiricilerinizi yazmanız gerekecek.

Örneğin.

<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>

Bu örnekte, bir Zarf Mesajlar içerebilir. Ancak, .NET'in varsayılan serileştiricisi, Message, ExampleMessageA ve ExampleMessageB arasında ayrım yapmaz. Yalnızca temel Message sınıfına ve sınıfından serileştirecektir.


0

Özel değişkenler / özellikler XML serileştirmede serileştirilmez, ancak ikili serileştirme içindedir.

Özel üyeleri kamu mülkleri aracılığıyla ifşa ediyorsanız, bunun sizi de alacağına inanıyorum - özel üyeler serileştirilmez, böylece genel üyelerin tümü boş değerlere başvurur.


Bu doğru değil. Kamu mülkünün belirleyicisi çağrılacak ve muhtemelen özel üyeyi belirleyecekti.
John Saunders
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.