【发布时间】:2015-05-01 01:47:40
【问题描述】:
我正在编写自己的二进制序列化程序,并针对游戏开发进行了优化。到目前为止,它功能齐全。它发出 IL 以生成预先给定类型序列的 [反] 序列化方法。唯一缺少的功能是通过引用序列化事物,目前所有内容都按值序列化。
为了实现它,我必须先了解它。这是我发现有点棘手。让我告诉你我在这几个例子中的理解:
示例 1(如 here 所示):
public class Person
{
public string Name;
public Person Friend;
}
static void Main(string[] args)
{
Person p1 = new Person();
p1.Name = "John";
Person p2 = new Person();
p2.Name = "Mike";
p1.Friend = p2;
Person[] group = new Person[] { p1, p2 };
var serializer = new DataContractSerializer(group.GetType(), null,
0x7FFF /*maxItemsInObjectGraph*/,
false /*ignoreExtensionDataObject*/,
true /*preserveObjectReferences : this is where the magic happens */,
null /*dataContractSurrogate*/);
serializer.WriteObject(Console.OpenStandardOutput(), group);
}
现在完全理解了。我们有一个根对象,它是数组,引用了两个不同的人。 p1.Friend 恰好是 p2。因此,我们不按值序列化p1.Friend,而是存储一个指向我们已经序列化的p2 的id。
但是;看看第二个例子:
static void Example2()
{
var p1 = new Person() { Name = "Diablo" };
var p2 = new Person() { Name = "Mephesto" };
p1.Friend = p2;
var serializer = new DataContractSerializer(typeof(Person), null, 0x7FFF, false, true, null);
serializer.WriteObject(Console.OpenStandardOutput(), p1);
Console.WriteLine("\n");
serializer.WriteObject(Console.OpenStandardOutput(), p2);
}
现在,根据我的理解:当序列化p1 时,序列化器将序列化p1.Name 和p1.Friend。在第二个WriteObject 中,序列化程序已经序列化了p2(即p1.Friend),所以它只是序列化一个指向p1.Friend 的id,而不是按值序列化它。
运行代码并查看输出似乎并非如此。在第二个输出中,我们看到序列化程序按值对p2 进行序列化,就好像它还没有遇到它一样……而我没有得到。就像内部有一个 id 计数器,在 WriteObject 结尾处被重置
这是另一个类似的例子:
static void Example3()
{
var p1 = new Person() { Name = "Diablo" };
var p2 = p1;
var serializer = new DataContractSerializer(typeof(Person), null, 0x7FFF, false, true, null);
serializer.WriteObject(Console.OpenStandardOutput(), p1);
Console.WriteLine("\n");
serializer.WriteObject(Console.OpenStandardOutput(), p2);
}
同样,第二个输出显示我们正在序列化 p2,就好像我们还没有遇到它的定义一样。
请注意,我没有出于任何特殊原因选择DataContractSerializer,任何支持通过引用进行序列化的序列化程序都可以。
我尝试在 DataContractSerializer 上进行 ILSpy,但我很快就迷路了,想不通。
- 在
Example2中,为什么序列化程序没有将 id 存储到p1.Friend序列化p2时? - 是“通过引用序列化” 仅适用于单个对象层次结构,或者它是如何工作的 一般? - 在我看来,通过引用进行序列化会自动 处理循环引用(A B),对吗?还是我需要 做其他事情以确保我不会陷入无限循环?
- 我认为通过引用进行序列化只有在应用时才有意义 关于引用类型而不是值类型,对吗?
我已经标记了 protobuf-net,因为它的相似之处在于它是一个二进制序列化程序并发出 IL。我很想听听那里是如何通过引用进行序列化的:p
【问题讨论】:
-
旁注:你不一定要用ILSpy,可以看这里的代码——referencesource.microsoft.com/#System.Runtime.Serialization/…
标签: c# serialization protobuf-net datacontractserializer