ProtoBuf DeepClone 在不使用代理项时返回空对象

本文关键字:返回 对象 代理 DeepClone ProtoBuf | 更新日期: 2023-09-27 18:37:05

我正在使用protobuf-net v2,并且有一个继承"List"的类,我不想序列化/克隆。
当我调用"DeepClone"(或反序列化)时,我得到克隆的对象为空。我可以将对象序列化为文件,它似乎按预期序列化,但运行时类型模型无法将其从 byte[] 反序列化回来。

我发现克服这个问题的唯一解决方案是使用代理。

如前所述,如果您要跳过"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 属性替换为"System.Serializable"属性时,即使没有代理项,它也会按预期反序列化 byte[]。

ProtoBuf DeepClone 在不使用代理项时返回空对象

这里的问题只是您通过以下方式明确关闭了列表处理

[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> { }
}