Reputation: 31
We have a base class and derived class. When we serialize a derived class, we want only the base class to be serialized. How can we achieve this in ProtoBuf-net.
Upvotes: 1
Views: 257
Reputation: 1062502
Edit: new things in v3; the following now works:
[ProtoContract(IgnoreUnknownSubTypes = true)]
public class Foo {}
which does exactly what you want here.
Currently protobuf-net is not very forgiving of unexpected types, because it really wants to be able to round-trip your data. In the 3.0 codebase, this is currently restricted to:
System.Data.Entity.DynamicProxies
NHibernate.Proxy.INHibernateProxy
, NHibernate.Proxy.DynamicProxy.IProxy
or NHibernate.Intercept.IFieldInterceptorAccessor
I'm open to discussing new additions that could be added to relax this - it would probably need a little discussion, but: it should be possible. Simply adding a marker interface or attribute that the library recognizes as a "ignore this type" token seems pretty reasonable! In fact, as I think about it: it would seem that we could just use [ProtoIgnore]
for this, by extending the AttributeTargets
for ProtoContractAttribute
, and adding a few lines to DynamicStub.ResolveProxies
.
Right now, the following "works" (for limited values of "works"), with outputs:
Trying BaseType...
Success; got BaseType
Trying KnownSubTypeViaInclude...
Success; got KnownSubTypeViaInclude
Trying UnknownSubType...
Unexpected sub-type: UnknownSubType
Trying LooksLikeEFProxy...
Success; got BaseType
Trying LooksLikeNHibernateProxy...
Success; got BaseType
code:
using ProtoBuf;
using System;
static class P
{
static void Main()
{
// works, trivially
Try<BaseType>();
// works, processes sub-type
Try<KnownSubTypeViaInclude>();
// fails, unexpected
Try<UnknownSubType>();
// works, processes base type only
Try<System.Data.Entity.DynamicProxies.LooksLikeEFProxy>();
Try<LooksLikeNHibernateProxy>();
}
static void Try<T>() where T : BaseType, new()
{
Console.WriteLine($"Trying {typeof(T).Name}...");
try
{
var clone = Serializer.DeepClone<BaseType>(new T());
Console.WriteLine($"Success; got {clone.GetType().Name}");
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
}
[ProtoContract]
[ProtoInclude(42, typeof(KnownSubTypeViaInclude))]
public class BaseType
{
}
public class KnownSubTypeViaInclude : BaseType { }
public class UnknownSubType : BaseType { }
public class LooksLikeNHibernateProxy : BaseType, NHibernate.Proxy.INHibernateProxy { }
namespace System.Data.Entity.DynamicProxies
{
public class LooksLikeEFProxy : BaseType { }
}
namespace NHibernate.Proxy // let's pretent to be NHibernate
{
public interface INHibernateProxy { }
}
Upvotes: 1