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

DataContract serializer doesn't work for similar types

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

根据 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 和数组,因为它们都使用相同的数据协定。

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

我写的应用只使用其中一种类型是很不切实际的,因为它是一种开发环境,开发者可以自由选择类型。

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

谢谢,

我有部分答案,但由于某些原因,在测试 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());

希望这能有所帮助。