首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >如何在ImmutableArray (C#)中使用MongoDB?

如何在ImmutableArray (C#)中使用MongoDB?
EN

Stack Overflow用户
提问于 2019-05-04 02:46:42
回答 1查看 585关注 0票数 1

我正试图把ImmutableArray (System.Collections.Immutable)保存在MongoDB中。

我尝试过MongoDB.Immutable,但它仅限于旧版本的不可变包,不支持ImmutableArray。

我尝试使用IBsonSerializer和IBsonSerializationProvider + SerializerBase创建自定义序列化程序,但没有成功。

代码语言:javascript
运行
复制
[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();
    }
}

代码语言:javascript
运行
复制
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.ImmutableArray1[System.Int32]', on 'MongoDB.Bson.Serialization.Serializers.EnumerableInterfaceImplementerSerializer2TValue,System.ArgumentException: GenericArguments,TItem‘违反了TValue类型的约束。-> System.TypeLoadException: GenericArguments,GenericArguments TItem‘违反了类型参数'TValue’的约束。

EN

回答 1

Stack Overflow用户

发布于 2019-09-06 23:06:52

通常您会实现EnumerableSerializerBase<TValue, TItem>,但是TValue被限制为class,而ImmutableArray<T>是一个struct,所以您需要一个能够处理struct的实现。

代码语言:javascript
运行
复制
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>的实现是非常直接的:

代码语言:javascript
运行
复制
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);
    }
}
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/55979043

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档