我正试图把ImmutableArray (System.Collections.Immutable)保存在MongoDB中。
我尝试过MongoDB.Immutable,但它仅限于旧版本的不可变包,不支持ImmutableArray。
我尝试使用IBsonSerializer和IBsonSerializationProvider + SerializerBase创建自定义序列化程序,但没有成功。
[BsonSerializer(typeof(BsonImmutableSerializer<>))]
public class BsonImmutableSerializer<T> : IBsonSerializer<ImmutableArray<T>>
{
public Type ValueType => typeof(ImmutableArray<T>);
public object Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args)
{
return context.Reader.ReadString().FromJson<ImmutableArray<T>>().ToImmutableArray();
}
public void Serialize(BsonSerializationContext context, BsonSerializationArgs args, object value)
{
context.Writer.WriteString(value.ToJson());
}
public void Serialize(BsonSerializationContext context, BsonSerializationArgs args, ImmutableArray<T> value)
{
context.Writer.WriteString(value.ToJson());
}
ImmutableArray<T> IBsonSerializer<ImmutableArray<T>>.Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args)
{
return context.Reader.ReadString().FromJson<ImmutableArray<T>>().ToImmutableArray();
}
}
或
public class ImmutableProvider<T> : IBsonSerializationProvider
{
public IBsonSerializer GetSerializer(Type type)
{
return type == typeof(ImmutableList<T>) ? new ImmutableSerializer<T>() : null;
}
}
public class ImmutableSerializer<T> : SerializerBase<ImmutableList<T>>
{
public override ImmutableList<T> Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args)
{
return context.Reader.ReadString().FromJson<List<T>>().ToImmutableList();
}
public override void Serialize(BsonSerializationContext context, BsonSerializationArgs args, ImmutableList<T> value)
{
context.Writer.WriteString(value.ToJson());
}
}
第一个解决方案引发此错误:
System.Runtime.Serialization.SerializationException:类型为'System.Collections.Immutable.ImmutableArray`1[System.Int32,mscorlib、Version=4.0.0.0、Culture=neutral、PublicKeyToken=b77a5c561934e089],其数据契约名为“ArrayOfint:http://schemas.microsoft.com/2003/10/Serialization/Arrays”。如果您正在使用DataContractResolver或将任何类型静态地添加到已知类型列表中,请考虑使用DataContractSerializer -例如,使用KnownTypeAttribute属性或将它们添加到传递给序列化程序的已知类型列表中。
第二次投掷:
'System.Collections.Immutable.ImmutableArray
1[System.Int32]', on 'MongoDB.Bson.Serialization.Serializers.EnumerableInterfaceImplementerSerializer
2TValue,System.ArgumentException: GenericArguments,TItem‘违反了TValue类型的约束。-> System.TypeLoadException: GenericArguments,GenericArguments TItem‘违反了类型参数'TValue’的约束。
发布于 2019-09-06 23:06:52
通常您会实现EnumerableSerializerBase<TValue, TItem>
,但是TValue
被限制为class
,而ImmutableArray<T>
是一个struct
,所以您需要一个能够处理struct
的实现。
using MongoDB.Bson;
using MongoDB.Bson.IO;
using MongoDB.Bson.Serialization;
using MongoDB.Bson.Serialization.Serializers;
using System;
using System.Collections.Generic;
public abstract class ValueEnumerableSerializerBase<TValue, TItem> : SerializerBase<TValue>, IBsonArraySerializer, IBsonSerializer
where TValue : struct, IEnumerable<TItem>
{
private readonly Lazy<IBsonSerializer<TItem>> _lazyItemSerializer;
protected ValueEnumerableSerializerBase()
: this(BsonSerializer.SerializerRegistry)
{
}
protected ValueEnumerableSerializerBase(IBsonSerializer<TItem> itemSerializer)
{
if (itemSerializer == null)
throw new ArgumentNullException(nameof(itemSerializer));
_lazyItemSerializer = new Lazy<IBsonSerializer<TItem>>(() => itemSerializer);
}
protected ValueEnumerableSerializerBase(IBsonSerializerRegistry serializerRegistry)
{
if (serializerRegistry == null)
throw new ArgumentNullException(nameof(serializerRegistry));
_lazyItemSerializer = new Lazy<IBsonSerializer<TItem>>(() => serializerRegistry.GetSerializer<TItem>());
}
public IBsonSerializer<TItem> ItemSerializer => _lazyItemSerializer.Value;
public override TValue Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args)
{
if (context == null)
throw new ArgumentNullException(nameof(context));
IBsonReader reader = context.Reader;
BsonType currentBsonType = reader.GetCurrentBsonType();
switch (currentBsonType)
{
case BsonType.Null:
{
reader.ReadNull();
return default;
}
case BsonType.Array:
{
reader.ReadStartArray();
object accumulator = CreateAccumulator();
while (reader.ReadBsonType() != BsonType.EndOfDocument)
{
TItem item = _lazyItemSerializer.Value.Deserialize(context);
AddItem(accumulator, item);
}
reader.ReadEndArray();
return FinalizeResult(accumulator);
}
default:
{
throw CreateCannotDeserializeFromBsonTypeException(currentBsonType);
}
}
}
public override void Serialize(BsonSerializationContext context, BsonSerializationArgs args, TValue value)
{
if (context == null)
throw new ArgumentNullException(nameof(context));
IBsonWriter writer = context.Writer;
if (value.Equals(default))
{
writer.WriteNull();
}
else
{
writer.WriteStartArray();
foreach (TItem item in EnumerateItemsInSerializationOrder(value))
_lazyItemSerializer.Value.Serialize(context, item);
writer.WriteEndArray();
}
}
public bool TryGetItemSerializationInfo(out BsonSerializationInfo serializationInfo)
{
IBsonSerializer<TItem> itemSerializer = _lazyItemSerializer.Value;
serializationInfo = new BsonSerializationInfo(null, itemSerializer, itemSerializer.ValueType);
return true;
}
protected abstract void AddItem(object accumulator, TItem item);
protected abstract object CreateAccumulator();
protected abstract IEnumerable<TItem> EnumerateItemsInSerializationOrder(TValue value);
protected abstract TValue FinalizeResult(object accumulator);
}
从这里开始,ImmutableArray<T>
的实现是非常直接的:
using MongoDB.Bson.Serialization;
using System.Collections.Generic;
using System.Collections.Immutable;
public class ImmutableArraySerializer<T> : ValueEnumerableSerializerBase<ImmutableArray<T>, T>, IChildSerializerConfigurable
{
public ImmutableArraySerializer()
{
}
public ImmutableArraySerializer(IBsonSerializer<T> itemSerializer)
: base(itemSerializer)
{
}
public ImmutableArraySerializer(IBsonSerializerRegistry serializerRegistry)
: base(serializerRegistry)
{
}
public IBsonSerializer WithItemSerializer(IBsonSerializer<T> itemSerializer)
{
return new ImmutableArraySerializer<T>(itemSerializer);
}
protected override void AddItem(object accumulator, T item)
{
((ImmutableArray<T>.Builder)accumulator).Add(item);
}
protected override object CreateAccumulator()
{
return ImmutableArray.CreateBuilder<T>();
}
protected override IEnumerable<T> EnumerateItemsInSerializationOrder(ImmutableArray<T> value)
{
return value;
}
protected override ImmutableArray<T> FinalizeResult(object accumulator)
{
return ((ImmutableArray<T>.Builder)accumulator).ToImmutable();
}
IBsonSerializer IChildSerializerConfigurable.ChildSerializer => ItemSerializer;
IBsonSerializer IChildSerializerConfigurable.WithChildSerializer(IBsonSerializer childSerializer)
{
return new ImmutableArraySerializer<T>((IBsonSerializer<T>)childSerializer);
}
}
https://stackoverflow.com/questions/55979043
复制相似问题