想象一下你有以下课程
[DataContract]
public class NamedList
{
[DataMember]
public string Name { get; set; }
[DataMember]
public IList<string> Items { get; private set; }
public DumpList(string name)
{
Name = name;
Items = new List<string>();
}
}
如果将其序列化为文件,则很容易,因为IList
后面的具体类是已知的并且可以序列化。
但是如果你试图将这个文件反序列化到内存中会发生什么呢? 它没有任何直接错误发生。
如果您尝试在列表中添加或删除某些内容,则会出现问题。在这种情况下,你会得到一个例外。此异常的根源于反序列化对象用作IList和Array的具体实现的情况。
在这个简单的例子中避免这个问题很容易。只是序列化具体的后备存储而不是公共属性,并在构造函数中进行更改:
[DataMember(Name = "Items")]
private List<string> _Items;
public IList<string> Items
{
get
{
return _Items;
}
}
public DumpList(string name)
{
Name = name;
_Items = new List<string>();
}
但更有趣的问题是:
答案 0 :(得分:3)
您可以使用DataContractSurrogate进行反序列化来解决此问题,将IList替换为List。
public class CustomDataContractSurrogate : IDataContractSurrogate
{
// The only function you should care about here. The rest don't do anything, just default behavior.
public Type GetDataContractType(Type type)
{
if (type.IsGenericType && type.GetGenericTypeDefinition().Equals(typeof(ICollection<>)))
{
return (typeof(List<>).MakeGenericType(type.GetGenericArguments().Single()));
}
return type;
}
public object GetObjectToSerialize(object obj, Type targetType)
{
return obj;
}
public object GetDeserializedObject(object obj, Type targetType)
{
return obj;
}
public object GetCustomDataToExport(MemberInfo memberInfo, Type dataContractType)
{
return null;
}
public object GetCustomDataToExport(Type clrType, Type dataContractType)
{
return null;
}
public void GetKnownCustomDataTypes(Collection<Type> customDataTypes)
{
}
public Type GetReferencedTypeOnImport(string typeName, string typeNamespace, object customData)
{
return null;
}
public CodeTypeDeclaration ProcessImportedType(CodeTypeDeclaration typeDeclaration, CodeCompileUnit compileUnit)
{
return typeDeclaration;
}
}
基本上就是这样,您只需要使用该代理创建DataContractSerializer实例并将其用于反序列化(对于序列化它无关紧要),例如:
var serializer = new DataContractSerializer(type, new Type[]{}, Int32.MaxValue, false, true, new CustomDataContractSurrogate());
或采取代理的任何其他构造函数。
或,(作为答案的奖励)如果您正在使用app / web.config定义的服务,您可以定义一个自定义行为,使用上述内容创建数据协定序列化程序替代:
public class CustomDataContractSerializerBehavior : DataContractSerializerOperationBehavior
{
public CustomDataContractSerializerBehavior(OperationDescription operation)
: base(operation)
{
}
public CustomDataContractSerializerBehavior(OperationDescription operation, DataContractFormatAttribute dataContractFormatAttribute)
: base(operation, dataContractFormatAttribute)
{
}
public override XmlObjectSerializer CreateSerializer(Type type, string name, string ns,
IList<Type> knownTypes)
{
return new DataContractSerializer(type, knownTypes, Int32.MaxValue, false, true, new CustomDataContractSurrogate());
}
public override XmlObjectSerializer CreateSerializer(Type type, XmlDictionaryString name,
XmlDictionaryString ns, IList<Type> knownTypes)
{
return new DataContractSerializer(type, knownTypes, Int32.MaxValue, false, true, new CustomDataContractSurrogate());
}
}
最后您可以使用此行为:
public static IMyDataServiceContract CreateService()
{
var factory = new ChannelFactory<IMyDataServiceContract>("MyServiceName");
SetDataContractSerializerBehavior(factory.Endpoint.Contract);
return factory.CreateChannel();
}
private static void SetDataContractSerializerBehavior(ContractDescription contractDescription)
{
foreach (OperationDescription operation in contractDescription.Operations)
{
ReplaceDataContractSerializerOperationBehavior(operation);
}
}
private static void ReplaceDataContractSerializerOperationBehavior(OperationDescription description)
{
DataContractSerializerOperationBehavior dcsOperationBehavior =
description.Behaviors.Find<DataContractSerializerOperationBehavior>();
if (dcsOperationBehavior != null)
{
description.Behaviors.Remove(dcsOperationBehavior);
description.Behaviors.Add(new CustomDataContractSerializerBehavior(description));
}
}
要完成作业,请在某处调用上面的CreateService来创建频道。
答案 1 :(得分:1)
如果使用存储类型信息的NetDataContractSerializer
以及序列化对象,则应解决问题。但是,它同时减少了与非.NET客户端的互操作性。