C# 使用对象序列化程序序列化列表

C# 使用对象序列化程序序列化列表,c#,xml,C#,Xml,我正在使用中定义的SerializableDictionary存储数据,并将其传递给WCF服务或从WCF服务传递数据。如果我使用值类型作为值,这很好,因为它们可以很容易地装箱成为objects。但是,如果我使用 newlist(){5,10},我得到一个异常: 类型System.Collections.Generic.List`1[[System.Int32,mscorlib,Version=4.0.0,Culture=neutral,PublicKeyToken=b77a5c561934e08

我正在使用中定义的
SerializableDictionary
存储
数据,并将其传递给WCF服务或从WCF服务传递数据。如果我使用值类型作为值,这很好,因为它们可以很容易地装箱成为
object
s。但是,如果我使用

newlist(){5,10}
,我得到一个异常:

类型System.Collections.Generic.List`1[[System.Int32,mscorlib,Version=4.0.0,Culture=neutral,PublicKeyToken=b77a5c561934e089]]不能在此上下文中使用

根据讨论,我应该使用
value.GetType()
初始化
XmlSerializer
;然而,虽然这让我可以序列化,但我不知道如何以一般方式反序列化回我的
SerializableDictionary

我不确定是否有一种方法可以在允许
作为我的类型参数的情况下彻底改变这一点-我可以将值序列化为二进制而不是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();
XmlSerializer serializer=新的XmlSerializer(typeof(SerializableDictionary));
SerializableDictionary dic=新的SerializableDictionary();
dic[“test”]=新列表({5,10});
StringBuilder sb=新的StringBuilder();
XmlWriter=XmlWriter.Create(sb);
序列化器。序列化(编写器,dic);
字符串ser=sb.ToString();
解决方案

感谢Nico Schertler给了我正确的答案。我在这里发布我的最终代码,以防有人需要。这与第一个链接中的原始代码是向后兼容的,因此由该代码序列化的任何内容都可以由下面的代码反序列化

[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

}
[XmlRoot(“字典”)]
公共类SerializableDictionary:Dictionary,IXmlSerializable
{
#区域“IXmlSerializable成员”
#区域“WriteXml”
public void WriteXml(XmlWriter)
{
//基本类型
string baseKeyType=typeof(TKey).AssemblyQualifiedName;
string baseValueType=typeof(TValue).AssemblyQualifiedName;
WriteAttributeString(“keyType”,baseKeyType);
WriteAttributeString(“valueType”,baseValueType);
foreach(此.Keys中的TKey键)
{
//开始
编写人。书面启动项(“项目”);
//钥匙
类型keyType=key.GetType();
XmlSerializer keySerializer=GetTypeSerializer(keyType.AssemblyQualifiedName);
writer.writeStart元素(“键”);
if(keyType!=typeof(TKey)){writer.WriteAttributeString(“type”,keyType.AssemblyQualifiedName);}
序列化(编写器,键);
writer.writeedelement();
//价值观
t值=此[键];
类型valueType=value.GetType();
XmlSerializer valueSerializer=GetTypeSerializer(valueType.AssemblyQualifiedName);
writer.writeStarteElement(“值”);
if(valueType!=typeof(TValue)){writer.WriteAttributeString(“type”,valueType.AssemblyQualifiedName);}
序列化(写入程序,值);
writer.writeedelement();
//结束
writer.writeedelement();
}
}
#端区
#区域“ReadXml”
公共void ReadXml(XmlReader)
{
bool waspempy=reader.isemptyelment;
reader.Read();
如果(为空)
{
返回;
}
//基本类型
string baseKeyType=typeof(TKey).AssemblyQualifiedName;
string baseValueType=typeof(TValue).AssemblyQualifiedName;
while(reader.NodeType!=XmlNodeType.EndElement)
{
//开始
reader.ReadStartElement(“项目”);
//钥匙
XmlSerializer keySerializer=GetTypeSerializer(读取器[“类型”]??baseKeyType);
reader.ReadStartElement(“密钥”);
TKey=(TKey)键序列化器。反序列化(读取器);
reader.ReadEndElement();
//价值观
XmlSerializer valueSerializer=GetTypeSerializer(读取器[“类型”]??baseValueType);
reader.ReadStartElement(“价值”);
TValue value=(TValue)valueSerializer.反序列化(读取器);
reader.ReadEndElement();
//贮藏
添加(键、值);
//结束
reader.ReadEndElement();
reader.MoveToContent();
}
reader.ReadEndElement();
}
#端区
#区域“GetSchema”
公共XmlSchema GetSchema()
{
返回null;
}
#端区
#端区
#区域“GetTypeSerializer”
私有静态只读字典_serializers=new Dictionary();
私有静态只读对象_deadbolt=new object();
私有XmlSerializer GetTypeSerializer(字符串类型)
{
if(!\u序列化程序.ContainsKey(类型))
{
锁(锁紧螺栓)
{
if(!\u序列化程序.ContainsKey(类型))
{
_Add(type,newxmlserializer(type.GetType(type));
}
}
}
返回_序列化程序[类型];
}
#端区
}

我只在类型与基类型不同时才写出该类型,以减少XML的长度,并且我保留了一个
XmlSerializer
s的静态列表,以防止到处显示它们。我必须在开始时写出提供的类型,以防止在每个节点上写出类型。

序列化的问题是,(反)序列化程序需要知道如何处理对象。
对象的序列化程序不知道如何序列化
列表

对于序列化,您已经给出了答案
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();
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
    }