1

このブログエントリSerializableDictionaryで定義されているデータを保存し、WCFサービスとの間でデータをやり取りしています。値タイプを値として使用する場合、これは正常に機能します。これは、値タイプを簡単にボックス化してsにすることができるためです。しかし、私が次のようなものを使用する場合<string, object>object

new List<int>() { 5, 10 }、例外が発生します:

タイプSystem.Collections.Generic.List`1[[System.Int32、mscorlib、Version = 4.0.0.0、Culture = neutral、PublicKeyToken=b77a5c561934e089]]はこのコンテキストでは使用できません。

ここでの説明によると、 ;value.GetType()を初期化するために使用する必要があります。XmlSerializerただし、これでシリアル化できますが、一般的な方法で逆シリアル化する方法がわかりませんSerializableDictionary

タイプ引数として許可しながらこれをきれいに変更する方法があるかどうかはわかりません<string, object>-値をXMLではなくバイナリにシリアル化してその方法で転送できます(同じコードがシリアル化と逆シリアル化されているので、私はそうではありません相互運用性が心配です)が、可能であればXMLを使用したいと思います。

編集

完全なコード例:

XmlSerializer serializer = new XmlSerializer(typeof(SerializableDictionary<string, object>));
SerializableDictionary<string, object> dic = new SerializableDictionary<string, object>();
dic["test"] = new List<int>() { 5, 10 };
StringBuilder sb = new StringBuilder();
XmlWriter writer = XmlWriter.Create(sb);
serializer.Serialize(writer, dic);
string ser = sb.ToString();

解決

正しい答えをくれたNicoSchertlerに感謝します。誰かがそれを必要とする場合に備えて、私はここに私の最終的なコードを投稿しています。これは最初のリンクの元のコードと下位互換性があるため、そのコードによってシリアル化されたものはすべて、以下によって逆シリアル化できます。

[XmlRoot("dictionary")]
public class SerializableDictionary<TKey, TValue> : Dictionary<TKey, TValue>, IXmlSerializable
{

    #region " IXmlSerializable Members "

    #region " WriteXml "

    public void WriteXml(XmlWriter writer)
    {
        // Base types
        string baseKeyType = typeof(TKey).AssemblyQualifiedName;
        string baseValueType = typeof(TValue).AssemblyQualifiedName;
        writer.WriteAttributeString("keyType", baseKeyType);
        writer.WriteAttributeString("valueType", baseValueType);

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

            // Key
            Type keyType = key.GetType();
            XmlSerializer keySerializer = GetTypeSerializer(keyType.AssemblyQualifiedName);

            writer.WriteStartElement("key");
            if (keyType != typeof(TKey)) { writer.WriteAttributeString("type", keyType.AssemblyQualifiedName); }
            keySerializer.Serialize(writer, key);
            writer.WriteEndElement();

            // Value
            TValue value = this[key];
            Type valueType = value.GetType();
            XmlSerializer valueSerializer = GetTypeSerializer(valueType.AssemblyQualifiedName);

            writer.WriteStartElement("value");
            if (valueType != typeof(TValue)) { writer.WriteAttributeString("type", valueType.AssemblyQualifiedName); }
            valueSerializer.Serialize(writer, value);
            writer.WriteEndElement();

            // End
            writer.WriteEndElement();
        }
    }

    #endregion

    #region " ReadXml "

    public void ReadXml(XmlReader reader)
    {
        bool wasEmpty = reader.IsEmptyElement;
        reader.Read();

        if (wasEmpty)
        {
            return;
        }

        // Base types
        string baseKeyType = typeof(TKey).AssemblyQualifiedName;
        string baseValueType = typeof(TValue).AssemblyQualifiedName;

        while (reader.NodeType != XmlNodeType.EndElement)
        {
            // Start
            reader.ReadStartElement("item");

            // Key
            XmlSerializer keySerializer = GetTypeSerializer(reader["type"] ?? baseKeyType);
            reader.ReadStartElement("key");
            TKey key = (TKey)keySerializer.Deserialize(reader);
            reader.ReadEndElement();

            // Value
            XmlSerializer valueSerializer = GetTypeSerializer(reader["type"] ?? baseValueType);
            reader.ReadStartElement("value");
            TValue value = (TValue)valueSerializer.Deserialize(reader);
            reader.ReadEndElement();

            // Store
            this.Add(key, value);

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

    #endregion

    #region " GetSchema "

    public XmlSchema GetSchema()
    {
        return null;
    }

    #endregion

    #endregion

    #region " GetTypeSerializer "

    private static readonly Dictionary<string, XmlSerializer> _serializers = new Dictionary<string, XmlSerializer>();
    private static readonly object _deadbolt = new object();
    private XmlSerializer GetTypeSerializer(string type)
    {
        if (!_serializers.ContainsKey(type))
        {
            lock (_deadbolt)
            {
                if (!_serializers.ContainsKey(type))
                {
                    _serializers.Add(type, new XmlSerializer(Type.GetType(type)));
                }
            }
        }
        return _serializers[type];
    }

    #endregion

}

XMLの長さを抑えるために、基本型とは異なる場合にのみ型を書き出します。また、 XmlSerializersの静的リストを保持して、それらがいたるところに存在しないようにします。各ノードで型が書き出されないようにするために、最初に提供された型を書き出す必要がありました。

4

2 に答える 2

3

シリアル化の問題は、(デ)シリアライザーがオブジェクトの処理方法を知る必要があることです。のシリアライザーobjectは、をシリアル化する方法を知りませんList<int>

シリアル化については、あなたはすでにあなたの質問に答えを与えました。value.GetType()値のタイプを判別するために使用します。さらに、タイプ自体を保存する必要があります。これは、タイプ()の文字列表現を使用して簡単に実現できますtype.AssemblyQualifiedName

TValue value = this[key];

var type = value.GetType();
XmlSerializer valueSerializer = new XmlSerializer(type);

writer.WriteStartElement("type");
writer.WriteString(type.AssemblyQualifiedName); 
//you can use FullName if you don't need to address external libraries
writer.WriteEndElement();

writer.WriteStartElement("content");
valueSerializer.Serialize(writer, value);
writer.WriteEndElement();

デシリアライズの場合は、タイプを読み取り、値をデシリアライズする必要があります。

reader.ReadStartElement("value");

reader.ReadStartElement("type");
var typename = reader.ReadContentAsString();
reader.ReadEndElement();
var type = Type.GetType(typename);
XmlSerializer valueSerializer = new XmlSerializer(type);

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

reader.ReadEndElement();
于 2013-02-25T18:38:39.980 に答える
0

リンクで参照しているクラスで、次の手順を実行します

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

namespace sampleLogin
{

    [XmlRoot("dictionary")]
    public class SerializableDictionary<TKey, TValue> : Dictionary<TKey, TValue>, IXmlSerializable
    {
        #region IXmlSerializable Members

        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];
                var type = value.GetType();//new line added here
                valueSerializer = new XmlSerializer(type);//New line added here 
                valueSerializer.Serialize(writer, value);
                writer.WriteEndElement();
                writer.WriteEndElement();
            }
        }
        #endregion
    }
于 2013-02-25T19:48:26.183 に答える