Reputation: 531
I have project that user can develop plugin for it. In their plugins, they must extend a abstract base class. In core of my project, load plugins (dlls) dynamically and new these classes.
base class in core of code:
[ProtoContract]
public abstract class BaseOutput
{
public string OutputName {get;}
[ProtoMember(1)]
public int X { get; set; }
}
sample of plugin (in other project):
[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; }
}
I know that over the BaseOutput I must add [ProtoInclude(10, typeof(MyOutput ))] but when I develop core of my application don't know the plugins that user will be add to program. But I want can to serialize all classes extend the BaseOutput with protobuf.
What is the solution?
Upvotes: 2
Views: 543
Reputation: 1062502
It is possible to configure this type of relationship at runtime with protobuf-net via the RuntimeTypeModel
API, as per the example shown below. However: it is vitally important that the key used (42
in the example) is reliable and deterministic every time your app runs. Meaning: you would need some way of reliably getting 42
for your specific plugin type every time, regardless of whether somebody adds/removes other plugins (which means: just ordering them alphabetically may not be enough). Also: the 42
must be unique among the different plugins that are loaded.
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());
}
}
Upvotes: 4