1

素晴らしいライブラリ Marc と SO に関するすべての回答に感謝します。

http://code.google.com/p/protobuf-net/downloads/listの .NET 4.0.zip で protobuf-net r480.zip を使用しています。これは最新の安定版リリースですか?

カスタム コレクションのシリアル化に問題があります。

public static void TestSerialization() {
    using (var stream = new MemoryStream()) {
        var b1 = new B1 { 1 };
        // Throws System.ArgumentException: Repeated data (a list, collection, etc) has inbuilt behaviour and cannot be subclassed
        Serializer.Serialize(stream, b1);
    }

    using (var stream = new MemoryStream()) {
        var b2 = new B2 { 2 };
        Serializer.Serialize(stream, b2);
        stream.Position = 0;
        var b2Deserialized = Serializer.Deserialize<B2>(stream);

        // This fails because b2Deserialized.Count is 0.
        Assert.AreEqual(1, b2Deserialized.Count);
    }

    using (var stream = new MemoryStream()) {
        RuntimeTypeModel.Default[typeof(A2<int>)].AddSubType(1000, typeof(B2));
        var b2 = new B2 { 2 };
        // Throws System.ArgumentException: Repeated data (a list, collection, etc) has inbuilt behaviour and cannot be subclassed
        Serializer.Serialize(stream, b2);
    }
}

[ProtoContract]
[ProtoInclude(1000, typeof(B1))]
public class A1<T> : List<T> { }

[ProtoContract]
public class B1 : A1<int> { }

[ProtoContract]
public class A2<T> : List<T> { }

[ProtoContract]
public class B2 : A2<int> { }

Anser Marc に感謝します。リストを使用するだけの場合、Proto 属性を削除するとうまくいきます。残念ながら、実際のコードはもっと複雑です。派生コレクションには他の値が含まれています (実際のコードでは、テンプレート パラメーターは int ではなく Entity 型であり、コレクション内のメンバーはコレクション内の要素の親への参照です)。これはより良い表現です。

    public static void TestSerialization() {
        using (var stream = new MemoryStream()) {
            var b = new B { 23 };
            b.SomeValue = "abc";
            Serializer.Serialize(stream, b);

            stream.Position = 0;
            var deserialized = Serializer.Deserialize<B>(stream);
            Assert.AreEqual(1, deserialized.Count);
            Assert.AreEqual(b[0], deserialized[0]);

            // This fails because deserialized.SomeValue == null
            Assert.AreEqual(b.SomeValue, deserialized.SomeValue);
        }
    }

    public class A<T> : List<T> { }

    public class B : A<int>
    {
        [ProtoMember(1)]
        public string SomeValue;
    }
4

1 に答える 1

1

IMO エラー メッセージは非常に明確です。継承はリストではサポートされていません。これは、リストにはプレースホルダーがないため、この情報を保存する場所がないためです。XML 用語で (protobuf は XML とはまったく異なることに注意してください)、次の出力のようになります (XmlSerializer に精通している場合)。

[XmlElement("item")]
public List<Foo> Items { get; set; }

どの出力だけ:

<item>...</item>
<item>...</item>
<item>...</item>

(ただし、「アイテム」ノードはありません - リスト自体について何か言える場所はどこにもありません)

あなたがその継承で何を表現しようとしているのかを理解しようとしています。率直に言って、有用なものは何も見当たりません。リストには組み込みの動作があるため、これらのコントラクトを定義する必要はまったくありませ。それらをリストとして使用するだけです。

一般的な意味では、リストを継承するのではなく、カプセル化する方が通常は適切です。

于 2012-07-23T15:01:43.307 に答える