I am using version 2 of ProtoBuf-net, and currently I'm geting the error "Unable to determine member: A"
Is it possible to create a run-time model for Protobuf-net when we use ClassOfType<T>? If so, can anyone spot what I'm missing in the below code?
btw: this request is modelled off of Deserialize unknown type with protobuf-net I could get a version of this going just fine... but they are using an abstract base class, not a generic class of T.
THIS IS A WORKING EXAMPLE (stuff that wasn't working is removed).
using System;
using System.IO;
using NUnit.Framework;
using ProtoBuf;
using ProtoBuf.Meta;
namespace ProtoBufTestA2
{
[TestFixture]
public class Tester
{
[Test]
public void TestMsgBaseCreateModel()
{
var BM_SD = new Container<SomeDerived>();
using (var o = BM_SD) {
o.prop1 = 42;
o.payload = new SomeDerived();
using (var d = o.payload) {
d.SomeBaseProp = -42;
d.SomeDerivedProp = 62;
}
}
var BM_SB = new Container<SomeBase>();
using (var o = BM_SB) {
o.prop1 = 42;
o.payload = new SomeBase();
using (var d = o.payload) {
d.SomeBaseProp = 84;
}
}
var model = TypeModel.Create();
model.Add(typeof(Container<SomeDerived>), true); // BM_SD
model.Add(typeof(Container<SomeBase>), true); // BM_SB
model.Add(typeof(SomeBase), true); // SB
model.Add(typeof(SomeDerived), true); // SD
model[typeof(SomeBase)].AddSubType(50, typeof(SomeDerived)); // SD
var ms = new MemoryStream();
model.SerializeWithLengthPrefix(ms, BM_SD, BM_SD.GetType(), ProtoBuf.PrefixStyle.Base128, 0);
model.SerializeWithLengthPrefix(ms, BM_SB, BM_SB.GetType(), ProtoBuf.PrefixStyle.Base128, 0);
ms.Position = 0;
var o1 = (Container<SomeDerived>)model.DeserializeWithLengthPrefix(
ms
, null
, typeof(Container<SomeDerived>), PrefixStyle.Base128, 0);
var o2 = (Container<SomeBase>)model.DeserializeWithLengthPrefix(
ms
, null
, typeof(Container<SomeBase>), PrefixStyle.Base128, 0);
}
}
[ProtoContract]
public class Container<T> : IDisposable
{
[ProtoMember(1)]
public int prop1 { get; set; }
[ProtoMember(2)]
public T payload { get; set; }
public void Dispose() { }
}
[ProtoContract]
public class AnotherDerived : SomeDerived, IDisposable
{
[ProtoMember(1)]
public int AnotherDerivedProp { get; set; }
public override void Dispose() { }
}
[ProtoContract]
public class SomeDerived : SomeBase, IDisposable
{
[ProtoMember(1)]
public int SomeDerivedProp { get; set; }
public override void Dispose() { }
}
[ProtoContract]
public class SomeBase : IDisposable
{
[ProtoMember(1)]
public int SomeBaseProp { get; set; }
public virtual void Dispose() { }
}
[ProtoContract]
public class NotInvolved : IDisposable
{
[ProtoMember(1)]
public int NotInvolvedProp { get; set; }
public void Dispose() { }
}
[ProtoContract]
public class AlsoNotInvolved : IDisposable
{
[ProtoMember(1)]
public int AlsoNotInvolvedProp { get; set; }
public void Dispose() { }
}
}
Request
This is minor, but it'd be nice if
(Container<SomeDerived>)model.DeserializeWithLengthPrefix(...)
could also be implemented like this
model.DeserializeWithLengthPrefix<Container<SomeDerived>>(...):
btw: I'm starting to dig into the protobuf-net implementation, and I'm starting to notice some interesting methods like this. Something to come back to later I guess:
public MetaType Add(int fieldNumber, string memberName, Type itemType, Type defaultType);
Discussion:
when I saw the way you could deserialize to an abstract base type in the link above, I thought, yes, that's closer to what was thinking. Could we deserialize to the open generic Container<> first, and then cast more specifically if we need to in different assemblies. Maybe I'm getting mixed up a little here.
You could think of it in terms of Tupple<TBase,TPayload>. Or a variation like Tupple<TBase,Lazy<TPayload>> maybe. It's not that different to List<T>. There are some TreeTypeThings<T> that I have too, but I don't need to serialize/deserialize them (yet).
I had a non-generic sequence working, so it isn't a show stopper. My first implementation could be more efficient. I think I can do better on that with existing protobuf-net features though.
I like the cleaner generic way of working with these ideas. Although I can get to the same destination manually, Generics make other things possible.
re: clarification
everything can be defined ahead of time by the caller. (btw: You've got me thinking about the run-time only scenario now, but no, I don't need that).