ProtoBuf DeepClone возвращает пустой объект, если не используется суррогат

Я использую protobuf-Net v2 и у меня есть класс, который наследует "Список", который я не хочу сериализовать / клонировать.
когда я вызываю "DeepClone" (или десериализацию), я получаю клонированный объект пустым. Я могу сериализовать объект в файл, и он, кажется, сериализуется, как и ожидалось, но RuntimeTypeModel не может десериализовать его обратно из байта [].

Единственное решение, которое я нашел, чтобы преодолеть эту проблему, это использовать суррогат.

как уже было сказано, если вы пропускаете "SetSurrogate", клон проваливается. Есть ли другой вариант, чтобы решить это?

прилагаются:

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; }
}

Еще одна вещь, которую я обнаружил, - когда вы заменяете атрибут ProtoContract из класса "Custom" на атрибут "System.Serializable", он десериализует байт [], как и ожидалось, даже без суррогата.

1 ответ

Решение

Проблема здесь просто в том, что вы явно отключили обработку списка с помощью:

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

Который, как следует из названия и документация проверяет:

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

Итак: ничего полезного не осталось, как Custom<T> не имеет других членов-данных для сериализации.

Итак: если вы не используете суррогат, не отключайте обработку списка. Основное назначение этой опции - для крайних случаев, когда что-то, что должно быть "объектом", также имеет функции, которые делают его соблазнительно похожим на список (все потребности protobuf-net IEnumerable[<T>] и удобный Add(T) метод).


[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> { }
}
Другие вопросы по тегам