Search code examples
c#protobuf-neteyeshot

How to serialize derived class into Eyeshot proprietary file format


I am trying to serialize custom EntityData class into Eyeshot proprietary file format. There is a great article about this (https://devdept.zendesk.com/hc/en-us/articles/360003318873-Eyeshot-Proprietary-File-Format),
it works fine if I serialize base class, however I can't serialize a class that is derived from my base class. Here is a sample, I tried to keep it as small as possible(please read comments along the way):

public class BaseClass
{
    public int Id { get; set; }
    public virtual BaseClassSurrogate ConvertToSurrogate() { return new BaseClassSurrogate(this); }
}
public class BaseClassSurrogate : Surrogate<BaseClass>
{
    public BaseClassSurrogate(BaseClass myBaseClass) : base(myBaseClass) { }
    public int Id { get; set; }
    protected override BaseClass ConvertToObject()
    {
        var baseClass = new BaseClass();
        CopyDataToObject(baseClass);
        return baseClass;
    }
    protected override void CopyDataFromObject(BaseClass obj) { Id = obj.Id; }
    protected override void CopyDataToObject(BaseClass obj) { obj.Id = this.Id; }
    public static implicit operator BaseClass(BaseClassSurrogate surrogate) { return surrogate?.ConvertToObject(); }
    public static implicit operator BaseClassSurrogate(BaseClass source) { return source?.ConvertToSurrogate(); }
}

And my derived class with its surrogate implementation:

public class DerivedClass : BaseClass
{
    public int Number { get; set; }
    public override BaseClassSurrogate ConvertToSurrogate() { return new DerivedClassSurrogate(this); }
}

public class DerivedClassSurrogate : BaseClassSurrogate
{
    public DerivedClassSurrogate(DerivedClass baseClass) : base(baseClass) { }
    public int Number { get; set; }
    protected override BaseClass ConvertToObject()
    {
        var derivedClass= new DerivedClass();
        CopyDataToObject(derivedClass);
        return derivedClass;
    }
    protected override void CopyDataFromObject(BaseClass obj)
    {
        if (obj is DerivedClass derivedClass)
            Number = derivedClass.Number;
        base.CopyDataFromObject(obj);
    }
    protected override void CopyDataToObject(BaseClass obj)
    {
        if (obj is DerivedClass derivedClass)
            derivedClass.Number = Number;
        base.CopyDataToObject(obj);
    }
    //I don't understand do I need to call these in derived class as well?
    //public static implicit operator BaseClass(BaseClassSurrogate surrogate) { return surrogate?.ConvertToObject(); }
    //public static implicit operator BaseClassSurrogate(BaseClass source) { return source?.ConvertToSurrogate(); }
}

And here is FillModel method from FileSerializer class:

protected override void FillModel()
{
    base.FillModel();

    Model.Add(typeof(BaseClass), false)
         .SetSurrogate(typeof(BaseClassSurrogate));

    MetaType mt1 = Model[typeof(BaseClassSurrogate)]
        .Add(1, "Id");

    mt1.SetCallbacks(null, null, "BeforeDeserialize", null); 
    mt1.UseConstructor = false; 

    Model.Add(typeof(DerivedClass), false)
    .SetSurrogate(typeof(DerivedClassSurrogate));

    MetaType mt2 = Model[typeof(DerivedClassSurrogate)]
        .Add(1, "Number");

    mt2.SetCallbacks(null, null, "BeforeDeserialize", null); 
    mt2.UseConstructor = false;
}

This code gives me error:"No suitable conversion operator found for surrogate DerivedClass/DerivedClassSurrogate". Any help would be highly appreciated.


Solution

  • In FillModel() method you forgot to specify the hierarchy for your custom classes, try in this way:

    protected override void FillModel()
    {
        base.FillModel();
    
        Model.Add(typeof(BaseClass), false)
            .AddSubType(1001, typeof(DerivedClass))
            .SetSurrogate(typeof(BaseClassSurrogate));
        
        Model[typeof(BaseClassSurrogate)]
            .AddSubType(1001, typeof(DerivedClassSurrogate))
            .Add(1, "Id")
            .SetCallbacks(null, null, "BeforeDeserialize", null)
            .UseConstructor = false; 
        
        Model[typeof(DerivedClassSurrogate)]
            .Add(1, "Number")
            .UseConstructor = false;
    }