如何在c#中序列化/反序列化不可变列表类型
如果我定义了一个类
[DataContract()] class MyObject { [DataMember()] ImmutableList Strings { get; private set} }
ImmutableList
类型来自immutables库https://www.nuget.org/packages/Microsoft.Bcl.Immutable 。 请注意,类ImmutableList没有默认构造函数或可变的Add方法。 将内容添加到列表中即可获取表单。
myList = myList.Add("new string");
我是否可以为.NET序列化机制添加一些自定义支持以支持此类型并向其显示如何对其进行反序列化?
目前,在反序列化时只会跳过该集合,尽管可以将其序列化。
通过IDataContractSurrogate接口还有另一种干净的方法。 DataContractSerializer允许您为非可序列化对象提供代理。 下面是ImmutableList
的示例和测试用例。 它使用reflection,可能可以由比我更聪明的人优化,但在这里。
测试用例
using FluentAssertions; using System.Collections.Immutable; using System.IO; using System.Linq; using System.Runtime.Serialization; using System.Text; using System.Xml; using Xunit; namespace ReactiveUI.Ext.Spec { [DataContract(Name="Node", Namespace="https://foo.com/")] class Node { [DataMember()] public string Name; } [DataContract(Name="Fixture", Namespace="https://foo.com/")] class FixtureType { [DataMember()] public ImmutableList Nodes; public FixtureType(){ Nodes = ImmutableList .Empty.AddRange( new [] { new Node(){Name="A"} , new Node(){Name="B"} , new Node(){Name="C"} }); } } public class ImmutableSurrogateSpec { public static string ToXML(object obj) { var settings = new XmlWriterSettings { Indent = true }; using (MemoryStream memoryStream = new MemoryStream()) using (StreamReader reader = new StreamReader(memoryStream)) using (XmlWriter writer = XmlWriter.Create(memoryStream, settings)) { DataContractSerializer serializer = new DataContractSerializer ( obj.GetType() , new DataContractSerializerSettings() { DataContractSurrogate = new ImmutableSurrogateSerializer() } ); serializer.WriteObject(writer, obj); writer.Flush(); memoryStream.Position = 0; return reader.ReadToEnd(); } } public static T Load(Stream data) { DataContractSerializer ser = new DataContractSerializer ( typeof(T) , new DataContractSerializerSettings() { DataContractSurrogate = new ImmutableSurrogateSerializer() } ); return (T)ser.ReadObject(data); } public static T Load (string data) { using (var stream = new MemoryStream(Encoding.UTF8.GetBytes(data))) { return Load (stream); } } [Fact] public void ShouldWork() { var o = new FixtureType(); var s = ToXML(o); var oo = Load(s); oo.Nodes.Count().Should().Be(3); var names = oo.Nodes.Select(n => n.Name).ToList(); names.ShouldAllBeEquivalentTo(new[]{"A", "B", "C"}); } } }
实施
using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; using System.Linq.Expressions; using System.Reflection; using System.Runtime.Serialization; namespace ReactiveUI.Ext { class ImmutableListListConverter { public static ImmutableList ToImmutable( List list ) { return ImmutableList .Empty.AddRange(list); } public static List ToList(ImmutableList list){ return list.ToList(); } public static object ToImmutable( object list ) { return ToImmutable(( List ) list); } public static object ToList(object list){ return ToList(( ImmutableList ) list); } } static class ImmutableListListConverter { static ConcurrentDictionary, Func
一种方法是使用代理可变列表并使用OnSerializing和OnDeserialized挂钩
[DataContract()] class MyObject { public ImmutableList Strings { get; private set} [DataMember(Name="Strings")] private List _Strings; [OnSerializing()] public void OnSerializing(StreamingContext ctxt){ _Strings = Strings.ToList(); } [OnDeserialized()] public void OnDeserialized(StreamingContext ctxt){ Strings = ImmutableList .Empty.AddRange(_Strings); } }
它并不是非常漂亮,但正如Marc Gravell在他的回答中指出的那样, DataContract序列化程序在不可变集合方面受到打破,并且没有简单的钩子来教它如何在没有上述类型的黑客的情况下表现。
UPDATE
DataContract序列化程序没有被破坏。 有一种方法可以将代理人挂钩。请参阅这个单独的答案,显示另一种技术。
https://stackoverflow.com/a/18957739/158285
嘿; 我可以想象这里发生了什么…生成的代码可能正在做(释义):
var list = obj.Strings; while(CanReadNextItem()) { list.Add(ReadNextItem()); }
问题是BCL不可变API会要求您每次捕获结果,即
var list = obj.Strings; while(CanReadNextItem()) { list = list.Add(ReadNextItem()); } obj.Strings = list; // the private set is not a problem for this
预先存在的列表反序列化代码不能以这种方式工作,因为它从来不需要 – 实际上,有许多不同的Add
实现,其中一些返回需要忽略的非void结果。
缺少一个非公共构造函数也可能会使它有点不高兴,但如果这是主要问题 ,我会在尝试创建非空列表时期望exception。
当然,在性能方面, list = list.Add(...)
API 可能不是最合适的API(尽管它应该工作)。
我最近在这个主题上发表了博客(在protobuf-net的背景下,现在已经更新以适应这些集合类型): http : //marcgravell.blogspot.co.uk/2013/09/fun-with-immutable- collections.html希望这篇博客文章能够解释为什么这些差异意味着它不能很好地与现有的序列化技术相结合,以及如何更新序列化库以使用这种情况。
要直接回答这个问题,我会说答案很简单: 因为尚未对DataContractSerializer
进行必要的更改以支持不可变集合 。 我不知道是否有计划解决这个问题。 但是:我高兴地宣布:“在protobuf-net中工作”; p
上述就是C#学习教程:如何在c#中序列化/反序列化不可变列表类型分享的全部内容,如果对大家有所用处且需要了解更多关于C#学习教程,希望大家多多关注—计算机技术网(www.ctvol.com)!
本文来自网络收集,不代表计算机技术网立场,如涉及侵权请联系管理员删除。
ctvol管理联系方式QQ:251552304
本文章地址:https://www.ctvol.com/cdevelopment/1003064.html