2

Tuple<Guid, int[]>C# 4.0 では、 DataContractSerializer を使用してシリアル化と逆シリアル化を試みています。Guidtype 、 type int[]、および typeのシリアライズとデシリアライズに成功しましたTuple<Guid, int>。type をシリアル化しようとすると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シリアル化できる型を含んでいれば、シリアル化に問題はないように思えます。

4

2 に答える 2

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 の一部にしたい場合は簡単です。

于 2013-05-13T19:55:33.287 に答える