1

私はprotobuf-netv2を使用していて、シリアル化/複製したくない「リスト」を継承するクラスを持っています。
「DeepClone」(または逆シリアル化)を呼び出すと、複製されたオブジェクトが空になります。オブジェクトをファイルにシリアル化でき、期待どおりにシリアル化されているようですが、RuntimeTypeModelは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; }
}

私が見つけたもう1つのことは、クラス「Custom」のProtoContract属性を「System.Serializable」属性に置き換えると、サロゲートがなくても期待どおりにbyte[]が逆シリアル化されることです。

4

1 に答える 1

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> { }
}
于 2012-06-18T20:16:58.937 に答える