1

I'm using protobuf-net v2 and have a class that inherits "List" that I wan't to serialize/clone.
when I'm calling "DeepClone" (or deserialize) I'm getting the cloned object empty. I can serialize the object into file and it seems to be serialized as expected but the RuntimeTypeModel can't deserialized it back from the byte[].

the single solution I've found to overcome this issue is to use surrogate.

as said, if you're skipping the "SetSurrogate" the clone is failed. is there any other option to solve it?

attached:

class Program
{
    static void Main(string[] args)
    {
        RuntimeTypeModel model = RuntimeTypeModel.Create();
        model[typeof(Custom<string>)].SetSurrogate(typeof(Surrogate<string>));

        var original = new Custom<string> { "C#" };
        var clone = (Custom<string>)model.DeepClone(original);
        Debug.Assert(clone.Count == original.Count);
    }
}

[ProtoContract(IgnoreListHandling = true)]
public class Custom<T> : List<T> { }

[ProtoContract]
class Surrogate<T>
{
    public static implicit operator Custom<T>(Surrogate<T> surrogate)
    {
        Custom<T> original = new Custom<T>();
        original.AddRange(surrogate.Pieces);
        return original;
    }

    public static implicit operator Surrogate<T>(Custom<T> original)
    {
        return original == null ? null : new Surrogate<T> { Pieces = original };
    }

    [ProtoMember(1)]
    internal List<T> Pieces { get; set; }
}

Another thing I've found is when you're replacing the ProtoContract attribute from the class "Custom" with "System.Serializable" attribute, it deserializing the byte[] as expected even without surrogate.

Tamir
  • 3,833
  • 3
  • 32
  • 41

1 Answers1

1

The problem here is simply the fact that you explicitly turned off the list-handling, via:

[ProtoContract(IgnoreListHandling = true)]
public class Custom<T> : List<T> { }

Which, as the name suggests and the documentation verifies:

/// <summary>
/// If specified, do NOT treat this type as a list, even if it looks like one.
/// </summary>
public bool IgnoreListHandling {...}

So: there was nothing useful left to do, as Custom<T> doesn't have any other data-members to serialize.

So: if you aren't using the surrogate, don't disable list-handling. The main purpose of this option is for edge-cases where something that is intended to be an "object" also has features that make it look temptingly like a list (all protobuf-net needs is IEnumerable[<T>] and a handy Add(T) method).


[TestFixture]
public class SO11034791
{
    [Test]
    public void Execute()
    {
        RuntimeTypeModel model = RuntimeTypeModel.Create();

        var original = new Custom<string> { "C#" };
        var clone = (Custom<string>)model.DeepClone(original);
        Assert.AreEqual(1, clone.Count);
        Assert.AreEqual("C#", clone.Single());
    }
    public class Custom<T> : List<T> { }
}
Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900
  • I dropped the call to SetSurrogate and remove the IgnoreListHandling and the cloned object is empty. did I missed something? – Tamir Jun 19 '12 at 08:51
  • @Tamir I have my current test harness (which passes) above - do you have something different? Have I misunderstood your question? – Marc Gravell Jun 19 '12 at 09:08
  • ok, now it works fine. but can you tell me please, when I have type that inherit List like Custom but contain additional members, this is when I should IgnoreListHandling and use the surrogate? – Tamir Jun 19 '12 at 10:14
  • @Tamir as with XmlSerializer and a few others, something is typically *either* a list, *or* a data entity. You could probably *spoof* the list by disabling list handling, but having a `[ProtoMember(n)] private IList InnerList { get { return this; } } ` - any use? – Marc Gravell Jun 19 '12 at 10:37
  • yes, I thought about that option but I'm getting into running system that I can't change the types. thank you for answering, it was very helpful. – Tamir Jun 19 '12 at 11:45
  • @Tamir I could conceivably do something to make that spoofing happen internally - a bit of a hack, but it could be *done*... in theory – Marc Gravell Jun 19 '12 at 11:48