解决实现 ISerialized 的对象的循环引用

2024-04-16

我正在编写自己的 IFormatter 实现,但我想不出一种方法来解决两个都实现 ISerialized 的类型之间的循环引用。

这是通常的模式:

[Serializable]
class Foo : ISerializable
{
    private Bar m_bar;

    public Foo(Bar bar)
    {
        m_bar = bar;
        m_bar.Foo = this;
    }

    public Bar Bar
    {
        get { return m_bar; }
    }

    protected Foo(SerializationInfo info, StreamingContext context)
    {
        m_bar = (Bar)info.GetValue("1", typeof(Bar));
    }

    public void GetObjectData(SerializationInfo info, StreamingContext context)
    {
        info.AddValue("1", m_bar);
    }
}

[Serializable]
class Bar : ISerializable
{
    private Foo m_foo;

    public Foo Foo
    {
        get { return m_foo; }
        set { m_foo = value; }
    }

    public Bar()
    { }

    protected Bar(SerializationInfo info, StreamingContext context)
    {
        m_foo = (Foo)info.GetValue("1", typeof(Foo));
    }

    public void GetObjectData(SerializationInfo info, StreamingContext context)
    {
        info.AddValue("1", m_foo);
    }
}

然后我这样做:

Bar b = new Bar();
Foo f = new Foo(b);
bool equal = ReferenceEquals(b, b.Foo.Bar); // true

// Serialise and deserialise b

equal = ReferenceEquals(b, b.Foo.Bar);

如果我使用开箱即用的 BinaryFormatter 来序列化和反序列化 b,则上述引用相等性测试将返回 true,正如人们所期望的那样。但我无法想象在我的自定义 IFormatter 中实现此目的的方法。

在非 ISerialized 情况下,一旦解决了目标引用,我就可以使用反射简单地重新访问“挂起”对象字段。但对于实现 ISerialized 的对象,无法使用 SerializationInfo 注入新数据。

有人能指出我正确的方向吗?


这种情况的原因是FormatterServices.GetUninitializedObject http://msdn.microsoft.com/en-us/library/system.runtime.serialization.formatterservices.getuninitializedobject.aspx方法。一般的想法是,如果您有对象 A 和 B,它们在各自的对象中相互引用SerializationInfo,您可以按如下方式反序列化它们:

(出于本解释的目的,(SI,SC)指类型的反序列化构造函数,即采用SerializationInfo and a StreamingContext.)

  1. 首先选择一个要反序列化的对象。选择哪一个并不重要,只要您不选择值类型即可。假设你选A。
  2. Call GetUninitializedObject to allocate(但不初始化) A 类型的实例,因为您还没有准备好调用它(SI,SC)构造函数。
  3. 以通常的方式构建B,即创建一个SerializationInfo对象(其中将包括对现在半反序列化的 A 的引用)并将其传递给 B 的(SI,SC)构造函数。
  4. 现在您拥有了所需的所有依赖项初始化你分配的 A 对象。创建它的SerializationInfo对象并调用 A(SI,SC)构造函数。您可以通过反射在现有实例上调用构造函数。

The GetUninitializedObject方法是纯粹的 CLR 魔法 - 它创建一个实例,而无需调用构造函数来初始化该实例。它基本上将所有字段设置为零/空。

这就是为什么我们警告您不要在对象中使用子对象的任何成员的原因。(SI,SC)构造函数 - 可以分配子对象,但此时尚未初始化。这也是原因IDeserializationCallback接口,它使您有机会在保证完成所有对象初始化之后和返回反序列化对象图之前使用您的子对象。

The 对象管理器 http://msdn.microsoft.com/en-us/library/system.runtime.serialization.objectmanager.aspx类可以为您完成所有这些(以及其他类型的修复)。然而,考虑到反序列化的复杂性,我总是发现它的记录相当少,所以我从未花时间尝试弄清楚如何正确使用它。它使用一些更多的魔法来执行步骤 4,使用一些优化的 CLR 内部反射来调用(SI,SC)构造函数更快(我将其计时速度大约是公共方式的两倍)。

最后,有些对象图涉及无法反序列化的循环。一个例子是当你有两个周期时IObjectReference实例(我已经测试过BinaryFormatter对此,它会抛出异常)。另一个我怀疑的是如果你有只涉及装箱值类型的循环 https://stackoverflow.com/q/3640963/89434.

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

解决实现 ISerialized 的对象的循环引用 的相关文章

  • asp.net net.mail - 在调试模式下将所有电子邮件路由到不同的电子邮件地址

    无论如何 有没有办法让所有电子邮件发送到不同的地址System Web HttpContext Current IsDebuggingEnabled是真的 或者我是否需要一个新的类来用于到处发送电子邮件 我会设置一个 SMTP 服务器 并让
  • 多个 Visual Studio 项目抱怨临时文件丢失,因此无法打开。错误代码 &H80070003

    我在终端服务器上运行 Visual Studio 2010 并且已经运行了一段时间 问题相对较少 今天早上 我启动了我的电脑 在英国的长周末期间 似乎出现了以下问题 我有很多项目 但不是我的所有项目 也不是给定解决方案中的所有项目 抱怨无法
  • 如何在.NET 中编写安全/正确的多线程代码?

    今天我必须修复一些使用线程的旧 VB NET 1 0 代码 问题在于从工作线程而不是 UI 线程更新 UI 元素 我花了一些时间才发现可以使用 InvokeRequired 断言来查找问题 除了上面提到的并发修改问题之外 还可能遇到死锁 竞
  • .NET 图形重影

    我正在为我们正在开发的新应用程序制作一个示例 GUI 我已经决定了语言 但我可以使用任何第 3 方 DLL 或插件或任何我需要的东西 以使 GUI 尽可能无缝地工作 他们希望它非常像 mac ubuntu vista Windows 7 所
  • Parallel.For 和 Break() 误解?

    我正在研究 For 循环中的并行性中断 看完之后this http tipsandtricks runicsoft com CSharp ParallelClass html and this http reedcopsey com 201
  • 在 C# 中将 ulong 映射到 long ?

    我正在尝试将 ulong 映射到 long 反之亦然 将 uint 映射到 int 反之亦然 如下所示 为了将值保存在具有签名类型的 MS SQL 数据库中仅限整数和大整数 我这样做是因为我必须检查 在数据库中 一个数字 uint ulon
  • lambda 表达式是多线程的吗?

    lambda 表达式是多线程的吗 假设当你将数学公式编写为 lambda 方法时 当你将其传递给另一个方法时 它会是多线程的吗 不是100 清楚你问的是什么 您是否想问 lambda 是否自然地在不同的线程上运行 如果是这样 则它们只是 S
  • 父窗体中的居中消息框[重复]

    这个问题在这里已经有答案了 有没有一种简单的方法可以在 net 2 0中将MessageBox居中于父窗体中 我在 C 中确实需要这个并发现中心消息框 C http bytes com topic c sharp answers 26712
  • 是否可以使用.NET 跟踪文件操作?

    当以某种方式调用文件操作 例如打开或关闭 时 我是否可以在操作系统继续请求之前处理它 如果可能的话可以通过以下方式取消它 NET http en wikipedia org wiki NET Framework 如果 NET没有这样的能力
  • 如何将 ConcurrentDictionary 转换为字典?

    我有一个 ConcurrentDictionary 对象 我想将其设置为 Dictionary 对象 不允许在它们之间进行转换 那么我该怎么做呢 The ConcurrentDictionary
  • 我如何移动粘性/捕捉 wpf 窗口

    当我移动 主 窗口时 我想移动两个或更多粘性窗口 我想做这样的事情 private void MainWindow PreviewMouseMove object sender MouseEventArgs e if e LeftButto
  • 查询 dns 别名

    我找到了一些code http msdn microsoft com en us library system net dns gethostbyaddress VS 71 aspx来自 msdn 站点 下面包含代码 看起来它将返回给定服务
  • EF数据库首先如何针对数据库更改更新模型?

    在班级图书馆Ado net Entity Data Model已生成 POCO 类 这些是第一次生成的 但数据库更改并未得到反映 在edmx图表右键单击并选择Update Model from Database显示新创建的表 但即使选择添加
  • .NET 迭代器包装抛出 API

    我有一个带有 API 的类 它允许我请求对象 直到它抛出一个IndexOutOfBoundsException 我想将它包装到一个迭代器中 以便能够编写更清晰的代码 但是 我需要捕获异常以停止迭代 static IEnumerable It
  • 可能有相同的合同,相同的绑定,相同的地址,但不同的端口?

    我有需要通过 basicHTTPBinding 进行通信的手持设备 我有合同 一切都按照广告进行 我需要扩展它以轻松支持测试环境 培训 当然还有生产的更改 我选择了端口路线 认为我可以公开具有端口差异的不同端点 并根据端口决定我想要来自哪个
  • 为什么该字符串的长度比其中的字符数长?

    这段代码 string a abc string b A C Console WriteLine Length a 0 a Length Console WriteLine Length b 0 b Length outputs Lengt
  • FileInfo.BaseName 存在于 PowerShell 中,但不存在于直接 .NET 中

    为什么在 NET 中System IO FileInfo对象没有BaseName属性 但我可以通过 PowerShell 使用该属性 例如 FolderItems Get ChildItem Path C Where Object isno
  • C# 中单个 & 符号的第二个含义是什么?

    我在 C 中使用了单个与号 来表示 检查second条件语句即使第一个是false 但以下似乎是不同的意思 of 总而言之 谁能解释一下如何i 1在下面的例子中有效吗 List
  • 使用 ContractNamespace 属性设置 WCF DataContract 命名空间

    在设计我的服务时 我决定要自定义出现在生成的 WSDL 中的名称空间 对于数据合同 我遇到了合约命名空间 http msdn microsoft com en us library system runtime serialization
  • 服务器响应 PASV 命令返回的地址与建立 FTP 连接的地址不同

    System Net WebException 服务器响应 PASV 命令返回的地址与建立 FTP 连接的地址不同 在 System Net FtpWebRequest CheckError 在 System Net FtpWebReque

随机推荐