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());
希望这能有所帮助。
我有一个应用程序,我需要为不同但相似的类型使用数据协定序列化程序:
- 通用列表
- 通用集合
- 数组
根据 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());
希望这能有所帮助。