DataContract序列化程序不适用于类似的类型

时间:2017-07-03 07:39:27

标签: c# .net serialization datacontractserializer

我有一个应用程序,我需要将数据协定序列化程序用于不同但类似的类型:

  • 通用列表
  • 通用馆藏
  • 阵列

根据Scrobi的要求,这是一个完整的模型示例:

[DataContract]
public class Model
{
    public Model()
    {
        List = new List<int>(new[] {1, 2, 3});
        Collection = new Collection<int>(new[] {4, 5, 6});
        Array = new[] {7, 8, 9};
    }

    [DataMember]
    public object List { get; set; }

    [DataMember]
    public object Collection { get; set; }

    [DataMember]
    public object Array { get; set; }

    public string SerializeMe()
    {
        var serializer = new DataContractSerializer(typeof(Model), GetKnownTypes());

        using (var stream = new MemoryStream())
        {
            serializer.WriteObject(stream, this); // exception

            return Encoding.UTF8.GetString(stream.GetBuffer());
        }
    }

    public static Type[] GetKnownTypes()
    {
        return new[]
        {
            typeof(List<int>),
            typeof(Collection<int>), // error
            typeof(int[]) // error
        };
    }
}

问题是:我无法同时添加通用List,Collection和数组,因为它们都使用相同的数据协定。

当我只使用其中一种集合类型时,我无法序列化其他集合类型,因为它们是未知的(数据合同存在,但对于另一种类型)。是的,这些字段必须是对象才能使其适用于我的情况(在实际应用程序中,我无法向它们添加属性)。

在我编写的应用程序中使用其中一种类型是非常不切实际的,因为它是一种开发环境,开发人员可以自由选择类型。

是否有针对此数据合同序列化程序限制的解决方法?

谢谢,

1 个答案:

答案 0 :(得分:1)

我有部分答案,但出于某种原因,在测试时Collection<int>在反序列化时会抛出错误。也许您可以使用它来找到完整的解决方案。

我创建了DataContractResolver,允许您覆盖xsi:type 有一些文档here

public class MyResolver : DataContractResolver
{
    public override bool TryResolveType(Type type, Type declaredType, DataContractResolver knownTypeResolver, out XmlDictionaryString typeName, out XmlDictionaryString typeNamespace)
    {
        string name = string.Empty;
        bool isFound = false;
        if (type.Name == "Int32[]")
        {
            name = "IntArray";
            isFound = true;
        }
        if (type.Name.Contains("List") && type.FullName.Contains("Int")) //find List<int>
        {
            name = "IntList";
            isFound = true;
        }
        if (type.Name.Contains("Collection") && type.FullName.Contains("Int")) //find Collection<int> 
        {
            name = "IntCollection";
            isFound = true;
        }

        if (isFound)
        {
            XmlDictionary dictionary = new XmlDictionary();
            typeName = dictionary.Add(name);
            typeNamespace = dictionary.Add("http://tempuri.com");
            return true;
        }

        return knownTypeResolver.TryResolveType(type, declaredType, knownTypeResolver, out typeName, out typeNamespace);
    }

    public override Type ResolveName(string typeName, string typeNamespace, Type declaredType, DataContractResolver knownTypeResolver)
    {
        if (typeName == "IntArray" )
        {
            return typeof(int[]);
        }
        if (typeName == "IntList")
        {
            return typeof(List<int>);
        }
        if (typeName == "IntCollection")
        {
            return typeof(Collection<int>);
        }


        return knownTypeResolver.ResolveName(typeName, typeNamespace, declaredType, null);
    }
}

然后,您不需要GetKnownTypes()并创建DataContractSerializer,如下所示:

var serializer = new DataContractSerializer(typeof(Model),null, int.MaxValue, false, false,null, new MyResolver());

希望这有点帮助。