使用 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");
}
}
}
}