R556を使用すると、次の複雑なシナリオの参照追跡が失敗します。テストのアサーションを参照してください。カスタムコレクションのサロゲートの代わりにshimクラスを使用しても、問題は変わりません。
どうやらSOは私の説明が気に入らないので、この役に立たないテキストによって、私の質問がロボットと一緒に集まることができるかもしれません。
using System.Collections.Generic;
using System.IO;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using ProtoBuf;
using ProtoBuf.Meta;
[TestClass]
public class UnitTest
{
[ProtoContract]
public class Whole
{
public Whole() { this.Parts = new PartCollection { Whole = this }; }
[ProtoMember(1)]
public readonly PartCollection Parts;
}
[ProtoContract]
public class Part
{
[ProtoMember(1, AsReference = true)]
public Whole Whole { get; set; }
}
public class PartCollection : List<Part>
{
public Whole Whole { get; set; }
}
[ProtoContract]
public class Assemblage
{
[ProtoMember(1)]
public readonly PartCollection Parts = new PartCollection();
}
[ProtoContract]
public class PartCollectionSurrogate
{
[ProtoMember(1)]
private PartCollection Collection { get; set; }
[ProtoMember(2)]
private Whole Whole { get; set; }
public static implicit operator PartCollectionSurrogate(PartCollection value)
{
if (value == null) return null;
return new PartCollectionSurrogate { Collection = value, Whole = value.Whole };
}
public static implicit operator PartCollection(PartCollectionSurrogate value)
{
if (value == null) return new PartCollection();
value.Collection.Whole = value.Whole;
return value.Collection;
}
}
[TestMethod]
public void TestMethod1()
{
RuntimeTypeModel.Default.Add(typeof(PartCollection), false).SetSurrogate(typeof(PartCollectionSurrogate));
using (var stream = new MemoryStream())
{
{
var whole = new Whole();
var part = new Part { Whole = whole };
whole.Parts.Add(part);
var assemblage = new Assemblage();
assemblage.Parts.Add(part);
Serializer.Serialize(stream, assemblage);
}
stream.Position = 0;
var obj = Serializer.Deserialize<Assemblage>(stream);
{
var assemblage = obj;
var whole = assemblage.Parts[0].Whole;
var referenceEqual = ReferenceEquals(assemblage.Parts[0], whole.Parts[0]);
// The following assertion fails.
Assert.IsTrue(referenceEqual);
}
}
}
}
これは、機能するサロゲートの代わりにshimクラスを使用して修正されたコードです。
using System.Collections.Generic;
using System.IO;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using ProtoBuf;
[TestClass]
public class UnitTest2
{
[ProtoContract]
public class Whole
{
public Whole() { this.Parts = new PartCollection { Whole = this }; }
public PartCollection Parts;
[ProtoMember(1)]
public PartCollectionData PartsData
{
get { return PartCollectionData.ToData(Parts); }
set { Parts = PartCollectionData.FromData(value); }
}
}
[ProtoContract]
public class Part
{
[ProtoMember(1, AsReference = true)]
public Whole Whole { get; set; }
}
[ProtoContract(IgnoreListHandling = true)]
public class PartCollection : List<Part>
{
public Whole Whole { get; set; }
}
[ProtoContract]
public class Assemblage
{
public PartCollection Parts = new PartCollection();
[ProtoMember(1)]
public PartCollectionData PartsData
{
get { return PartCollectionData.ToData(Parts); }
set { Parts = PartCollectionData.FromData(value); }
}
}
[ProtoContract]
public class PartCollectionData
{
[ProtoMember(1, AsReference = true)]
public List<Part> Collection { get; set; }
[ProtoMember(2, AsReference = true)]
public Whole Whole { get; set; }
public static PartCollectionData ToData(PartCollection value)
{
if (value == null) return null;
return new PartCollectionData { Collection = value, Whole = value.Whole };
}
public static PartCollection FromData(PartCollectionData value)
{
if (value == null) return null;
PartCollection result = new PartCollection { Whole = value.Whole };
if (value.Collection != null)
result.AddRange(value.Collection);
return result;
}
}
[TestMethod]
public void TestMethod1()
{
using (var stream = new MemoryStream())
{
{
var whole = new Whole();
var part = new Part { Whole = whole };
whole.Parts.Add(part);
var assemblage = new Assemblage();
assemblage.Parts.Add(part);
Serializer.Serialize(stream, assemblage);
}
stream.Position = 0;
var obj = Serializer.Deserialize<Assemblage>(stream);
{
var assemblage = obj;
var whole = assemblage.Parts[0].Whole;
Assert.AreSame(assemblage.Parts[0].Whole, whole.Parts[0].Whole, "Whole");
Assert.AreSame(assemblage.Parts[0], whole.Parts[0], "Part");
}
}
}
}
これが機能する修正されたサロゲートコードです。
using System.Collections.Generic;
using System.IO;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using ProtoBuf;
using ProtoBuf.Meta;
[TestClass]
public class UnitTest
{
[ProtoContract]
public class Whole
{
public Whole() { this.Parts = new PartCollection { Whole = this }; }
[ProtoMember(1)]
public PartCollection Parts;
}
[ProtoContract]
public class Part
{
[ProtoMember(1, AsReference = true)]
public Whole Whole { get; set; }
}
[ProtoContract(IgnoreListHandling = true)]
public class PartCollection : List<Part>
{
public Whole Whole { get; set; }
}
[ProtoContract]
public class Assemblage
{
[ProtoMember(1)]
public PartCollection Parts = new PartCollection();
}
[ProtoContract]
public class PartCollectionSurrogate
{
[ProtoMember(1, AsReference = true)]
public List<Part> Collection { get; set; }
[ProtoMember(2, AsReference = true)]
public Whole Whole { get; set; }
public static implicit operator PartCollectionSurrogate(PartCollection value)
{
if (value == null) return null;
return new PartCollectionSurrogate { Collection = value, Whole = value.Whole };
}
public static implicit operator PartCollection(PartCollectionSurrogate value)
{
if (value == null) return null;
PartCollection result = new PartCollection { Whole = value.Whole };
if (value.Collection != null)
result.AddRange(value.Collection);
return result;
}
}
[TestMethod]
public void TestMethod1()
{
RuntimeTypeModel.Default.Add(typeof(PartCollection), true).SetSurrogate(typeof(PartCollectionSurrogate));
using (var stream = new MemoryStream())
{
{
var whole = new Whole();
var part = new Part { Whole = whole };
whole.Parts.Add(part);
var assemblage = new Assemblage();
assemblage.Parts.Add(part);
Serializer.Serialize(stream, assemblage);
}
stream.Position = 0;
var obj = Serializer.Deserialize<Assemblage>(stream);
{
var assemblage = obj;
var whole = assemblage.Parts[0].Whole;
Assert.AreSame(assemblage.Parts[0].Whole, whole.Parts[0].Whole, "Whole");
Assert.AreSame(assemblage.Parts[0], whole.Parts[0], "Part");
}
}
}
}