C # Serialize унаследованный класс с Proto-Buf без использования ProtoInclude - PullRequest
0 голосов
/ 29 ноября 2018

У меня есть проект, который пользователь может разработать для него плагин.В своих плагинах они должны расширять абстрактный базовый класс.В ядре моего проекта загружайте плагины (dll) динамически и добавляйте новые классы.

базовый класс в ядре кода:

[ProtoContract]
public abstract class BaseOutput
{
    public string OutputName {get;}
    [ProtoMember(1)]
    public int X { get; set; }
}

образец плагина (в другом проекте):

[ProtoContract]
public class MyOutput : BaseOutput
{
    public override OutputName { get { return "MyOutput";} }
    [ProtoMember(11)]
    public double A { get; set; }
    [ProtoMember(12)]
    public double B { get; set; }
    [ProtoMember(13)]
    public double C { get; set; }
}

Я знаю, что поверх BaseOutput я должен добавить [ProtoInclude (10, typeof (MyOutput))]], но когда я разрабатываю ядро ​​своего приложения, не знаю плагинов, которые пользователь будет добавлять в программу.Но я хочу можно сериализовать все классы, расширить BaseOutput с помощью protobuf. * ​​1009 *

Какое решение?

1 Ответ

0 голосов
/ 29 ноября 2018

Можно настроить этот тип отношений во время выполнения с protobuf-net через API RuntimeTypeModel, как показано в примере ниже.Однако: жизненно важно важно, чтобы используемый ключ (42 в примере) был надежным и детерминированным каждый раз, когда ваше приложение запускает .Значение: вам понадобится какой-то способ надежно получение 42 для вашего конкретного типа плагина каждый раз, независимо от того, добавляет ли кто-нибудь / удаляет другие плагины (что означает: просто упорядочить их в алфавитном порядкеможет не хватить).Также: 42 должен быть уникальным среди различных загружаемых плагинов.


using ProtoBuf;
using ProtoBuf.Meta;

[ProtoContract]
public abstract class BaseOutput
{
    public abstract string OutputName { get; }
    [ProtoMember(1)]
    public int X { get; set; }
}

[ProtoContract]
public class MyOutput : BaseOutput
{
    public override string OutputName { get { return "MyOutput"; } }
    [ProtoMember(11)]
    public double A { get; set; }
    [ProtoMember(12)]
    public double B { get; set; }
    [ProtoMember(13)]
    public double C { get; set; }

    public override string ToString()
        => $"A={A}, B={B}, C={C}"; // to show working
}

class Program
{
    static void Main()
    {
        var pluginType = typeof(MyOutput); // after loading the plugin etc
        var baseType = RuntimeTypeModel.Default[typeof(BaseOutput)];
        baseType.AddSubType(42, pluginType);

        BaseOutput obj = new MyOutput { A = 1, B = 2, C = 3 };
        var clone = Serializer.DeepClone(obj);

        // outputs: A=1, B=2, C=3 - so: working (yay!)
        System.Console.WriteLine(clone.ToString());
    }
}
...