ここでの答えは「場合による」です。protobuf 仕様にはオブジェクト識別子/再利用が含まれていないため、通常(デフォルトでは) これはツリーのシリアル化であり、データは複製されます。
これは、すべてのデフォルトの動作で protobuf-net を使用して調べることができます。
using ProtoBuf;
using System;
using System.Collections.Generic;
using System.Linq;
class Program
{
static void Main()
{
Person mike = new Person { Name = "Mike" };
Person jack = new Person { Name = "Jack" };
jack.Parent = mike;
List<Person> people = new List<Person>();
people.Add(mike);
people.Add(jack);
var cloneOfEverything = Serializer.DeepClone(people);
var newMike = cloneOfEverything.Single(x => x.Name == "Mike");
var newJack = cloneOfEverything.Single(x => x.Name == "Jack");
Console.WriteLine(jack.Parent.Name); // writes Miks as expected
bool areSamePersonObject = ReferenceEquals(newMike, newJack.Parent);
// False ^^^
bool areSameStringInstance = ReferenceEquals(
newMike.Name, newJack.Parent.Name);
// True ^^^
}
}
[ProtoContract]
class Person
{
[ProtoMember(1)]
public string Name;
[ProtoMember(2)]
public Person Parent;
}
所見:
- ジャックの親は正しくマイクと呼ばれています
- しかし、同じように見えるのは別のオブジェクトインスタンスです
- これ
string
は同じインスタンスです - 実装の詳細として、protobuf-net には、データ内の同じ UTF-8 チャンクを検出し、同じstring
インスタンスを再利用して割り当てを回避するコードが含まれています - しかし、データはバイナリに 2 回含まれていました
- 情報のために、上記のツリーは24バイトかかります
ここで何が起こっているかを調査することでも、これを確認できます。
Person mike = new Person { Name = "Mike" };
mike.Parent = mike;
var clone = Serializer.DeepClone(mike);
ツリーとして記述しているため、次のエラーが発生します。
再帰の可能性が検出されました (オフセット: 1 レベル): 人
でも!ライブラリ固有の実装の詳細として、protobuf-net には、回すことができる多くのノブとダイヤルが含まれています。これらの 1 つは、オブジェクト ID に関連しています。Person
参照 ID で動作するように切り替えることができます。
[ProtoContract(AsReferenceDefault=true)]
class Person {...}
これにより、バイナリのデータが変更され (追加のマーカーを含めるため)、その結果、同じ行が機能するようになりました。
Person mike = new Person { Name = "Mike" };
mike.Parent = mike;
var clone = Serializer.DeepClone(mike);
bool areSamePersonObject = ReferenceEquals(clone, clone.Parent);
// ^^^ true
これは実装固有の詳細を使用しており、他の実装を混乱させる可能性があることに注意してください。
AsReferenceDefault
Person
ここでは、いつでも参照として扱われるべきであると述べています。より細かく制御するために、個別に使用できるオブジェクト[ProtoMember]
も含まれています。AsReference
ただし、簡単なチェックでは、現在正常に動作していないList<Person>
ことが示されているようです。調査する必要があります。もっともな理由があるかもしれませんが、現時点では考えられず、バグであると思われます。
AsReference
string
同じ文字列を繰り返し書き込むことを避けるために、メンバーに含めることもできます"Mike"
。string
このオプションは、同じことが何度も繰り返される場合に役立ちます。名前にもかかわらず、 を使用する場合string
、AsReference
は「参照の等価性」ではなく「文字列の等価性」として解釈されます。