我不想用任何序列化逻辑搞乱我们的BusinessObjects。 这就是为什么我想为每个单独的BusinessObject实现一个Surrogate,它封装了序列化和反序列化BusinessObject所必需的Data。 此外,它包含序列化后要执行的所有业务逻辑。
然而,词典中的引用跟踪似乎存在问题。请考虑以下示例:
//DataContracts:
public class SerializeClass
{
public Dictionary<string, SerializeDictionaryItem> MyDictionary { get; set; }
public List<SerializeDictionaryItem> MyList { get; set; }
}
[ProtoContract]
public class SerializeDictionaryItem
{
[ProtoMember(1)]
public string MyField { get; set; }
}
[ProtoContract(SkipConstructor = true)]
public class SerializeClassSurrogate
{
[ProtoMember(1000, AsReference = true)]
public Dictionary<string, SerializeDictionaryItem> MyDictionary { get; set; }
[ProtoMember(1001, AsReference = true)]
public List<SerializeDictionaryItem> MyList { get; set; }
public static implicit operator SerializeClass(SerializeClassSurrogate surrogate)
{
if (surrogate == null)
return null;
var serializeClass = new SerializeClass();
serializeClass.MyDictionary = surrogate.MyDictionary;
serializeClass.MyList = surrogate.MyList;
return serializeClass;
}
public static implicit operator SerializeClassSurrogate(SerializeClass serializeClass)
{
if (serializeClass == null)
return null;
var surrogate = new SerializeClassSurrogate();
surrogate.MyDictionary = serializeClass.MyDictionary;
surrogate.MyList = serializeClass.MyList;
return surrogate;
}
}
//Serialization Logic:
RuntimeTypeModel.Default[typeof(SerializeClass)].SetSurrogate(typeof(Surrogates.SerializeClassSurrogate));
var myDictionaryItem = new SerializeDictionaryItem();
myDictionaryItem.MyField = "ABC";
SerializeClass m = new SerializeClass() {MyDictionary = new Dictionary<string, SerializeDictionaryItem>()};
m.MyDictionary.Add("def", myDictionaryItem);
m.MyDictionary.Add("abc", myDictionaryItem);
m.MyList = new List<SerializeDictionaryItem>();
m.MyList.Add(myDictionaryItem);
m.MyList.Add(myDictionaryItem);
using (var writer = new StreamWriter(OutputDir + "proto.bin"))
{
Serializer.Serialize(writer.BaseStream, m);
}
using(var reader = new StreamReader(OutputDir + "proto.bin"))
{
var deserialized = Serializer.Deserialize<SerializeClass>(reader.BaseStream);
var areEqualInDictionary = deserialized.MyDictionary["def"] == deserialized.MyDictionary["abc"];
var areEqualInList = deserialized.MyList[0] == deserialized.MyList[1];
}
反序列化后,两个“areEqualIn ...”布尔应该是真的。但是,在反序列化期间,我得到以下异常:
“在反序列化期间,引用跟踪对象更改了引用”
这是一个错误还是我做错了什么?
/编辑: 这似乎与代理人的使用没有任何关系。如果我在没有它们的情况下尝试序列化,只需将SerializeClass更改为ProtoContract,并将其成员相应地更改为ProtoMembers,就会出现同样的问题。
顺便说一下。我正在使用protobuf-net v2 429
/ EDIT2: 也可以使用此代码激发此异常,该代码根本不需要字典:
public class SerializeClass
{
public string MyField { get; set; }
public SerializeClass GroupTrailerRef { get; set; }
}
[ProtoContract(SkipConstructor = true)]
public class SerializeClassSurrogate
{
[ProtoMember(1001)]
public string MyField { get; set; }
[ProtoMember(1002, AsReference = true)]
public SerializeClass GroupTrailerRef { get; set; }
public static implicit operator SerializeClass(SerializeClassSurrogate surrogate)
{
if (surrogate == null)
return null;
var serializeClass = new SerializeClass();
serializeClass.MyField = surrogate.MyField;
serializeClass.GroupTrailerRef = surrogate.GroupTrailerRef;
return serializeClass;
}
public static implicit operator SerializeClassSurrogate(SerializeClass serializeClass)
{
if (serializeClass == null)
return null;
var surrogate = new SerializeClassSurrogate();
surrogate.MyField = serializeClass.MyField;
surrogate.GroupTrailerRef = serializeClass.GroupTrailerRef;
return surrogate;
}
}
RuntimeTypeModel.Default[typeof(SerializeClass)].SetSurrogate(typeof(Surrogates.SerializeClassSurrogate));
//Serialization Code:
SerializeClass groupTrailer = new SerializeClass();
groupTrailer.MyField = "Group";
SerializeClass m = new SerializeClass() {};
m.GroupTrailerRef = groupTrailer;
m.MyField = "First";
SerializeClass k = new SerializeClass();
k.GroupTrailerRef = groupTrailer;
k.MyField = "Second";
var lst = new List<SerializeClass>();
lst.Add(m);
lst.Add(k);
using (var writer = new StreamWriter(OutputDir + "proto.bin"))
{
Serializer.Serialize(writer.BaseStream, lst);
}
using(var reader = new StreamReader(OutputDir + "proto.bin"))
{
var deserialized = Serializer.Deserialize<List<SerializeClass>>(reader.BaseStream);
var areEqual = deserialized[0].GroupTrailerRef == deserialized[1].GroupTrailerRef;
}
你有什么建议?我喜欢使用代理方法将序列化逻辑与业务对象分开。你认为我应该坚持“正常”的方式吗?但是在那种情况下,由于问题203 ......我再次陷入困境。
谢谢你, TH