微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

如何在c#中序列化/反序列化不可变列表类型

如果我定义了一个
[DataContract()]
class MyObject {
    [DataMember()]
    ImmutableList<string> Strings { get; private set}
}

ImmutableList< T> type来自immutables库https://www.nuget.org/packages/Microsoft.Bcl.Immutable.请注意,类ImmutableList没有认构造函数或可变Add方法.将内容添加到列表中即可获取表单.

myList = myList.Add("new string");

我是否可以为.NET序列化机制添加一些自定义支持支持此类型并向其显示如何对其进行反序列化?

目前,在反序列化时只会跳过该集合,尽管可以将其序列化.

解决方法

通过 IDataContractSurrogate接口还有另一种干净的方法. DataContractSerializer允许您为非可序列化对象提供代理.以下是ImmutableList< T>的示例和测试用例.它使用反射,可能可以由比我更聪明的人优化,但在这里.

测试用例

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="http://foo.com/")]
    class Node
    {
        [DataMember()]
        public string Name;
    }

    [DataContract(Name="Fixture",Namespace="http://foo.com/")]
    class FixtureType
    {
        [DataMember()]
        public ImmutableList<Node> Nodes;

        public FixtureType(){
            Nodes = ImmutableList<Node>.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<T>(Stream data)
        {
            DataContractSerializer ser = new DataContractSerializer
                  ( typeof(T),new DataContractSerializerSettings() { DataContractSurrogate = new ImmutableSurrogateSerializer() }
                  );
            return (T)ser.Readobject(data);
        }

        public static T Load<T>(string data)
        {
            using (var stream = new MemoryStream(Encoding.UTF8.GetBytes(data)))
            {
                return Load<T>(stream);
            }
        }

        [Fact]
        public void ShouldWork()
        {
            var o = new FixtureType();

            var s = ToXML(o);

            var oo = Load<FixtureType>(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<T>
    {
        public static ImmutableList<T> ToImmutable( List<T> list )
        {
            return ImmutableList<T>.Empty.AddRange(list);
        }

        public static List<T> ToList(ImmutableList<T> list){
            return list.ToList();
        }

        public static object ToImmutable( object list )
        {
            return ToImmutable(( List<T> ) list);
        }

        public static object ToList(object list){
            return ToList(( ImmutableList<T> ) list);
        }

    }

    static class ImmutableListListConverter {


        static ConcurrentDictionary<Tuple<string,Type>,Func<object,object>> _MethodCache 
            = new ConcurrentDictionary<Tuple<string,object>>();

        public static Func<object,object> CreateMethod( string name,Type genericType )
        {
            var key = Tuple.Create(name,genericType);
            if ( !_MethodCache.ContainsKey(key) )
            {
                _MethodCache[key] = typeof(ImmutableListListConverter<>)
                    .MakeGenericType(new []{genericType})
                    .getmethod(name,new []{typeof(object)})
                    .MakeLambda();
            }
            return _MethodCache[key];
        }
        public static Func<object,object> ToImmutableMethod( Type targettype )
        {
            return ImmutableListListConverter.CreateMethod("ToImmutable",targettype.GenericTypeArguments[0]);
        }

        public static Func<object,object> ToListMethod( Type targettype )
        {
            return ImmutableListListConverter.CreateMethod("ToList",targettype.GenericTypeArguments[0]);
        }

        private static Func<object,object> MakeLambda(this MethodInfo method )
        {
            return (Func<object,object>) method.CreateDelegate(Expression.GetDelegateType(
            (from parameter in method.GetParameters() select parameter.ParameterType)
            .Concat(new[] { method.ReturnType })
            .ToArray()));
        }

    }

    public class ImmutableSurrogateSerializer : IDataContractSurrogate
    {
        static ConcurrentDictionary<Type,Type> _TypeCache = new ConcurrentDictionary<Type,Type>();

        public Type GetDataContractType( Type targettype )
        {
            if ( _TypeCache.ContainsKey(targettype) )
            {
                return _TypeCache[targettype];
            }

            if(targettype.IsGenericType && targettype.GetGenericTypeDeFinition() == typeof(ImmutableList<>)) 
            {
                return _TypeCache[targettype] 
                    = typeof(List<>).MakeGenericType(targettype.GetGenericArguments());
            }
            else
            {
                return targettype;
            }
        }

        public object GetDeserializedobject( object obj,Type targettype )
        {
            if ( _TypeCache.ContainsKey(targettype) )
            {
               return ImmutableListListConverter.ToImmutableMethod(targettype)(obj);
            }
            return obj;
        }

        public object GetobjectToSerialize( object obj,Type targettype )
        {
            if ( targettype.IsGenericType && targettype.GetGenericTypeDeFinition() == typeof(ImmutableList<>) )
            {
               return ImmutableListListConverter.ToListMethod(targettype)(obj);
            }
            return obj;
        }

        public object GetCustomDataToExport( Type clrType,Type dataContractType )
        {
            throw new NotImplementedException();
        }

        public object GetCustomDataToExport( System.Reflection.MemberInfo memberInfo,Type dataContractType )
        {
            throw new NotImplementedException();
        }


        public void GetKNownCustomDataTypes( System.Collections.ObjectModel.Collection<Type> customDataTypes )
        {
            throw new NotImplementedException();
        }


        public Type GetReferencedTypeOnImport( string typeName,string typeNamespace,object customData )
        {
            throw new NotImplementedException();
        }

        public System.CodeDom.CodeTypeDeclaration ProcessImportedType( System.CodeDom.CodeTypeDeclaration typeDeclaration,System.CodeDom.CodeCompileUnit compileUnit )
        {
            throw new NotImplementedException();
        }

        public ImmutableSurrogateSerializer() { }
    }
}

原文地址:https://www.jb51.cc/csharp/98760.html

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐