如何序列化包含基本类型和基本类型数组的元组?

时间:2013-05-13 19:28:32

标签: c# c#-4.0 serialization tuples datacontractserializer

在C#4.0中,我正在尝试使用DataContractSerializer序列化和反序列化Tuple<Guid, int[]>。我已成功序列化并反序列化了Guid类型,输入int[]并输入Tuple<Guid, int>。如果我尝试序列化类型Tuple<Guid, int[]>,那么一切都会编译,但我得到以下运行时异常:

Type 'System.Int32[]' with data contract name 
'ArrayOfint:http://schemas.microsoft.com/2003/10/Serialization/Arrays'
is not expected. Consider using a DataContractResolver or add any types
not known statically to the list of known types - for example, by using
the KnownTypeAttribute attribute or by adding them to the list of known 
types passed to DataContractSerializer.

我的序列化和反序列化例程很简单:

public static string Serialize<T>(this T obj)
{
    var serializer = new DataContractSerializer(obj.GetType());
    using (var writer = new StringWriter())
    using (var stm = new XmlTextWriter(writer))
    {
        serializer.WriteObject(stm, obj);
        return writer.ToString();
    }
}

public static T Deserialize<T>(this string serialized)
{
    var serializer = new DataContractSerializer(typeof(T));
    using (var reader = new StringReader(serialized))
    using (var stm = new XmlTextReader(reader))
    {
        return (T)serializer.ReadObject(stm);
    }
}

为什么我会遇到此异常,我该怎么做才能解决这个问题或绕过它?在我看来,包含可序列化类型的Tuple应该没有序列化的麻烦。

2 个答案:

答案 0 :(得分:4)

这样的事情怎么样?

class Program
{
    public static class DataContractSerializerFactory<T>
    {
        private static IEnumerable<Type> GetTypeArguments(Type t, IEnumerable<Type> values)
        {
            if (t.IsGenericType)
                foreach (var arg in t.GetGenericArguments())
                    values = values.Union(GetTypeArguments(arg, values));
            else
                values = values.Union(new[] { t });
            return values;
        }

        public static DataContractSerializer Create()
        {
            return new DataContractSerializer(typeof(T), GetTypeArguments(typeof(T), new[] { typeof(T) }));
        }
    }

    static void Main(string[] args)
    {
        var x = Tuple.Create(Guid.NewGuid(), new[] { 1, 2, 3, 4, 5, 6 });

        var serializer = DataContractSerializerFactory<Tuple<Guid, int[]>>.Create();

        var sb = new StringBuilder();
        using (var writer = XmlWriter.Create(sb))
        {
            serializer.WriteObject(writer, x);
            writer.Flush();
            Console.WriteLine(sb.ToString());
        }
    }
}

编辑:应该为任何嵌套泛型工作。仅考虑基类型和叶类型参数。如果您希望中间容器也是KnownTypes的一部分,那应该很容易。

答案 1 :(得分:3)

错误消息告诉您需要做什么;问题是序列化程序不能立即识别本身是嵌入式内部序列化类型成员的数组。您只需要为其提供序列化该特定类型所需的元数据。

通常情况下,您可以通过将属性添加到DataContact来执行此操作,如下所示:

[DataContract]
[KnownType(typeof(int[]))]

但是,由于您要序列化Tuple而不是用户定义的类,因此您需要将其传递到the constructor:

var knownTypes = new List<Type> { typeof(int[]) };
var serializer = new DataContractSerializer(typeof(Tuple<Guid, int[]>), knownTypes);