12

XmlSerializer を使用して、T がインターフェイスである List(T) を永続化しようとしています。シリアライザーはインターフェイスが好きではありません。XmlSerializer を使用して異種オブジェクトのリストを簡単にシリアル化する簡単な方法があるかどうかに興味があります。ここに私が行くものがあります:

    public interface IAnimal
    {
        int Age();
    }
    public class Dog : IAnimal
    {
        public int Age()
        {
            return 1;
        }
    }
    public class Cat : IAnimal
    {
        public int Age()
        {
            return 1;
        }
    }

    private void button1_Click(object sender, RoutedEventArgs e)
    {
        var animals = new List<IAnimal>
        {
            new Dog(),
            new Cat()
        };

        var x = new XmlSerializer(animals.GetType());
        var b = new StringBuilder();
        var w = XmlTextWriter.Create(b, new XmlWriterSettings { NewLineChars = "\r\n", Indent = true });
        //FAIL - cannot serialize interface. Does easy way to do this exist?
        x.Serialize(w, animals);
        var s = b.ToString();    
    }
4

5 に答える 5

14

XmlSerializer も使用できますが、シリアル化するオブジェクト グラフに表示できるすべての型を含める必要があるため、拡張性が制限され、保守性が低下します。XmlSerializer のコンストラクターのオーバーロードを使用してそれを行うことができます。

var x = new XmlSerializer(animals.GetType(), new Type[] { typeof(Cat), typeof(Dog) });

また、XmlSerializer を使用する場合の注意事項がいくつかあります。ここで概説されているすべて (MSDN) - たとえば、「動的に生成されたアセンブリ」という見出しの下を見てください。

于 2010-09-13T23:21:34.120 に答える
8

XmlSerializer、デシリアライズ時に作成する型がわからないため、インターフェイスを処理できません。これを回避するには、IXmlSerializableインターフェースを実装して、シリアル化のその部分を自分で処理する必要があります。これにより、タイプを記録して再作成 (デシリアライズ) できるようになります。

以下のListOfIAnimalクラスは、ジェネリック リストを継承および拡張してList<IAnimal>、必要なインターフェイスを実装する方法を示しています。具象クラスが適切にシリアル化および逆シリアル化されていることを確認できるように、それぞれに余分な非インターフェイス フィールドを追加して、古いクラスを押しつぶしました。

ListOfIAnimalの代わりに新しい型を使用しているコードと比較するとList<IAnimal>、他の変更はほんの少しのリファクタリングです。

その完全なコードは、独自の .cs ファイルにコピーするだけで、最初の関数を呼び出してステップ実行します。

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

namespace Serialiser
{
    static class SerialiseInterface
    {
        public static void SerialiseAnimals()
        {
            String finalXml;

            // Serialize
            {
                var animals = new ListOfIAnimal{
                    new Dog() { Age = 5, Teeth = 30 },
                    new Cat() { Age = 6, Paws = 4 }
                };

                var xmlSerializer = new XmlSerializer(animals.GetType());
                var stringBuilder = new StringBuilder();
                var xmlTextWriter = XmlTextWriter.Create(stringBuilder, new XmlWriterSettings { NewLineChars = "\r\n", Indent = true });
                xmlSerializer.Serialize(xmlTextWriter, animals);
                finalXml = stringBuilder.ToString();
            }

            // Deserialise
            {
                var xmlSerializer = new XmlSerializer(typeof(ListOfIAnimal));
                var xmlReader = XmlReader.Create(new StringReader(finalXml));
                ListOfIAnimal animals = (ListOfIAnimal)xmlSerializer.Deserialize(xmlReader);
            }
        }
    }

    public class ListOfIAnimal : List<IAnimal>, IXmlSerializable
    {
        public ListOfIAnimal() : base() { }

        #region IXmlSerializable
        public System.Xml.Schema.XmlSchema GetSchema() { return null; }

        public void ReadXml(XmlReader reader)
        {
            reader.ReadStartElement("ListOfIAnimal");
            while (reader.IsStartElement("IAnimal"))
            {
                Type type = Type.GetType(reader.GetAttribute("AssemblyQualifiedName"));
                XmlSerializer serial = new XmlSerializer(type);

                reader.ReadStartElement("IAnimal");
                this.Add((IAnimal)serial.Deserialize(reader));
                reader.ReadEndElement(); //IAnimal
            }
            reader.ReadEndElement(); //ListOfIAnimal
        }

        public void WriteXml(XmlWriter writer)
        {
            foreach (IAnimal animal in this)
            {
                writer.WriteStartElement("IAnimal");
                writer.WriteAttributeString("AssemblyQualifiedName", animal.GetType().AssemblyQualifiedName);
                XmlSerializer xmlSerializer = new XmlSerializer(animal.GetType());
                xmlSerializer.Serialize(writer, animal);
                writer.WriteEndElement();
            }
        }
        #endregion
    }

    public interface IAnimal { int Age { get; set; } }
    public class Dog : IAnimal { public int Age { get; set;} public int Teeth { get; set;} }
    public class Cat : IAnimal { public int Age { get; set;} public int Paws { get; set;} }
}

私は読者の演習としてデシリアライズを残すことを考えましたが、コードはそれなしでは非常に役に立ちません。

于 2013-02-26T12:33:35.027 に答える
3

使用する必要がありますXmlSerializerか? これは の既知の問題XmlSerializerです。

BinaryFormatter を使用してストリームに保存できます。

BinaryFormatter bf = new BinaryFormatter();
MemoryStream ms = new MemoryStream();
bf.Serialize(ms, animals);

他の代替手段は、WCF を使用DataContractSerializerし、KnownType 属性を使用して型を提供することです。

于 2010-09-13T22:21:25.480 に答える
2

ExtendedXmlSerializerを使用できます。

var serializer = new ExtendedXmlSerializer();
var xml = serializer.Serialize(animals);

xml は次のようになります。

<?xml version="1.0" encoding="utf-8"?>
<ArrayOfIAnimal>
    <Dog type="Model.Dog" />
    <Cat type="Model.Cat" />
</ArrayOfIAnimal>
于 2016-09-22T08:02:42.213 に答える
0

簡単な方法は、[Serializable()] 装飾をクラスに追加し、IList を List に変更して、それが機能するかどうかを確認することです。

インターフェイスを使用する場合は、webturner の回答を参照してください。

于 2016-08-09T16:46:11.583 に答える