简体   繁体   English

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

[英]DataContract serializer doesn't work for similar types

I have an application where I need to use the data contract serializer for different, but similar types: 我有一个需要将数据协定序列化程序用于不同但相似类型的应用程序:

  • Generic Lists 通用列表
  • Generic Collections 通用集合
  • Arrays 数组

On request from Scrobi, here's a full model example: 根据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
        };
    }
}

The problem is: I can't add the generic List, Collection and the array at the same time, because all of them use the same data contract. 问题是:我不能同时添加通用List,Collection和数组,因为它们全部使用相同的数据协定。

When I only use one of the collection types, I am unable to serialize the other ones, because they are unknown (the data contract is present, but for the other type). 当我仅使用一种收集类型时,我无法序列化其他收集类型,因为它们是未知的(存在数据协定,但适用于另一种类型)。 And yes, the fields must be objects to make this work for my case (and in the real application, I cannot add attributes to them). 是的,这些字段必须是对象,以使其适合我的情况(在实际应用程序中,我无法向其添加属性)。

It is very impractical in the application I write to only use one of the types, as it is a kind of development environment and the developer can choose the type freely. 在我编写的应用程序中仅使用一种类型是非常不切实际的,因为它是一种开发环境,开发人员可以自由选择类型。

Is there any workaround against this limitation of the data contract serializer? 是否有针对此数据合同序列化程序限制的解决方法?

Thanks, 谢谢,

I have a partial answer but for some reason when testing the Collection<int> throws an error when deserialising. 我有一个部分答案,但是由于某种原因,在测试Collection<int>时反序列化时会引发错误。 Maybe you can work with this to find a full solution. 也许您可以使用它来找到完整的解决方案。

I created a DataContractResolver allowing you to override the xsi:type There is some documentation here 我创建了一个DataContractResolver让您覆盖xsi:type有一些文件在这里

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);
    }
}

You then don't need your GetKnownTypes() and create the DataContractSerializer like this: 然后,您不需要GetKnownTypes()并像这样创建DataContractSerializer

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

Hope this somewhat helps. 希望这会有所帮助。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM