4

Lets say I have some data

1: {
    1: 0.0
    2: 1
    3: "2"
    4: true
}

But at compile time I don't know the contract. At run-time however, I can load a data descriptor that tells me how many fields I have and what each type in each field will be. i.e.

new Type[]{
   typeof(double),
   typeof(int),
   typeof(string),
   typeof(bool)};

Q: How can I, at run-time, get protocol-buf to read (and write) the message from a stream given the data-description?

My current thinking is this: Create a type at run-time (emit) given the data description then have protocol-buf serialise/deserialise with that. Then access properties via reflection/dynamic. Not sure if this is a good idea though.

This is an alternative approach from Serialize object[] with Protobuf-net

Community
  • 1
  • 1
Meirion Hughes
  • 24,994
  • 12
  • 71
  • 122

1 Answers1

3

I wonder if your best bet might be to just use the extension member API; something like

[TestFixture]
public class SO25179186
{
    [Test]
    public void RuntimeMessageContract()
    {
        var adhoc = new AdHoc();
        Extensible.AppendValue<double>(adhoc, 1, 0.0);
        Extensible.AppendValue<int>(adhoc, 2, 1);
        Extensible.AppendValue<string>(adhoc, 3, "2");
        Extensible.AppendValue<bool>(adhoc, 4, true);

        var clone = Serializer.DeepClone(adhoc);
        Assert.AreNotSame(clone, adhoc);
        Assert.AreEqual(0.0, Extensible.GetValue<double>(clone, 1));
        Assert.AreEqual(1, Extensible.GetValue<int>(clone, 2));
        Assert.AreEqual("2", Extensible.GetValue<string>(clone, 3));
        Assert.AreEqual(true, Extensible.GetValue<bool>(clone, 4));
    }

    [ProtoContract]
    class AdHoc : Extensible {}
}

There is currently no other "adhoc object definition" API in protobuf-net. There are, however, variants of the above that work with Type rather than generics.

Note that you don't have to inherit from Extensible; you can also implement IExtensible manually. Extensible just does it conveniently. Note that IExtensible works in addition to any protobuf fields that are already declared on the type.

Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900
  • Almost there, but I would need to use non-generic: `Extensible.AppendValue(model, adhoc, 1, DataFormat.Default, Activator.CreateInstance(expectedType));` ... which works too. :) – Meirion Hughes Aug 07 '14 at 10:17
  • If I go the route of using Extensible, rather than Emitting a dynamic class, will I get performance penalties? i.e. the deserializer isn't compiled, etc? – Meirion Hughes Aug 07 '14 at 12:29