C# 具有许多未知类型的Protobuf

C# 具有许多未知类型的Protobuf,c#,protobuf-net,C#,Protobuf Net,当我在运行时不知道使用protobuf对哪些类型进行反序列化时,最好的方法是什么 目前,我正在考虑在类型的初始值设定项中扩展RuntimeTypeModel,这些类型是序列化的候选类型,这对于序列化来说似乎非常有效。但是当在不同的进程中进行反序列化时,我需要从用于序列化类型的某个地方加载相同的类型模型。是否可以将RuntimeTypeModel序列化到磁盘,以便在以后从磁盘再次读取序列化数据时重用它?理想情况下,我会将模型放入序列化流中,并拥有一个完整的自描述对象模型。或者我需要记录这些步骤并将

当我在运行时不知道使用protobuf对哪些类型进行反序列化时,最好的方法是什么

目前,我正在考虑在类型的初始值设定项中扩展RuntimeTypeModel,这些类型是序列化的候选类型,这对于序列化来说似乎非常有效。但是当在不同的进程中进行反序列化时,我需要从用于序列化类型的某个地方加载相同的类型模型。是否可以将RuntimeTypeModel序列化到磁盘,以便在以后从磁盘再次读取序列化数据时重用它?理想情况下,我会将模型放入序列化流中,并拥有一个完整的自描述对象模型。或者我需要记录这些步骤并将这些数据放在序列化流的前面吗

我们可以创建一个标头,其中包含实际数据的偏移量、运行时类型模型以及非常好的长度。或者有没有更好的方法来处理插件体系结构,在序列化时我注册了所有类型,但在反序列化过程中,我可能仍然需要从它们各自的程序集中加载一些类型,因为代码还没有被触及

using ProtoBuf;
using ProtoBuf.Meta;
using System.Collections.Generic;
using System.IO;

namespace protobuf
{
    [ProtoContract]
    public interface IAbstraction
    {
        [ProtoMember(1)]
        string Name { get; set; }
    }

    [ProtoContract]
    public class Base : IAbstraction
    {
        static Base()
        {
            ProtobufTypeModels.MainModel.Add(typeof(IAbstraction), true).AddSubType(101, typeof(Base));
        }

        [ProtoMember(1)]
        public string Name { get; set; }

        [ProtoMember(2, AsReference =true)]
        public List<IAbstraction> Instances = new List<IAbstraction>();
    }

    [ProtoContract]
    public class Next : Base
    {
        static Next()
        {
            ProtobufTypeModels.MainModel.Add(typeof(IAbstraction), true).AddSubType(100, typeof(Next));
        }

        [ProtoMember(1)]
        public string NextName { get; set; }
    }

    public static class ProtobufTypeModels
    {
        public static readonly RuntimeTypeModel MainModel = TypeModel.Create();
    }


    class Program
    {
        static void Main(string[] args)
        {
            Base b = new Base { Name = "Alois" };
            b.Instances.Add(new Next { Name = "Base", NextName = "Christian" });
            b.Instances.Add(new Base { Name = "SecondBase", Instances = b.Instances });
            var mem = new MemoryStream();
            ProtobufTypeModels.MainModel.Serialize(mem, b);
            mem.Position = 0;
            var deser = (Base) ProtobufTypeModels.MainModel.Deserialize(mem, null, typeof(Base));
        }
    }
}
使用ProtoBuf;
使用ProtoBuf.Meta;
使用System.Collections.Generic;
使用System.IO;
名称空间协议
{
[原始合同]
公共接口映射
{
[原成员(1)]
字符串名称{get;set;}
}
[原始合同]
公共类基:IAbstraction
{
静基座()
{
ProtobufTypeModels.MainModel.Add(typeof(IAbstraction),true).AddSubType(101,typeof(Base));
}
[原成员(1)]
公共字符串名称{get;set;}
[原成员(2,AsReference=true)]
公共列表实例=新列表();
}
[原始合同]
下一个公共类:Base
{
静态下一步()
{
ProtobufTypeModels.MainModel.Add(typeof(IAbstraction),true).AddSubType(100,typeof(Next));
}
[原成员(1)]
公共字符串NextName{get;set;}
}
公共静态类ProtobufTypeModels
{
public static readonly RuntimeTypeModel MainModel=TypeModel.Create();
}
班级计划
{
静态void Main(字符串[]参数)
{
Base b=新的Base{Name=“Alois”};
b、 Add(新的Next{Name=“Base”,NextName=“Christian”});
b、 Add(newbase{Name=“SecondBase”,Instances=b.Instances});
var mem=新内存流();
ProtobufTypeModels.MainModel.Serialize(mem,b);
记忆位置=0;
var deser=(Base)ProtobufTypeModels.MainModel.Deserialize(mem,null,typeof(Base));
}
}
}
随机思维:在完成初始化并将烘焙的序列化程序写入磁盘后,可以使用
.Compile(serializerName,dllPath)
;然后您可以引用它,使用
newserializername()
创建实例,然后从那里使用
.Serialize
etc方法。dll永远不会改变。这也意味着它不再需要处理任何元数据;无反射、无IL发射等


除此之外:我们可以在存储配置方面做一些更温和的事情,但是:protobuf net目前没有直接添加任何东西来支持它,对于您来说,拥有自己的定制配置数据可能更为重要,您只需在启动时使用这些数据。

序列化程序集并不是最好的事情,因为对于一个长期运行的过程,我需要为每个保存的文件加载一个新的程序集,因为太多(数千)个程序集,我可能会遇到内存泄漏问题加载到当前AppDomain中的程序集的个数。我想我会坚持记录Model.Add和AddSubtype调用,并将这些参数存储在流前面,以便在需要再次反序列化类型时重播API调用。