多次/跨不同图形恢复状态是否安全?

Is it safe to restore state multiple times / across different Graphics?

将一个 Graphics 对象的保存状态与另一个 Graphics 对象一起使用是否安全?例如,如以下示例所示。

Graphics g1 = ..;
Graphics g2 = ..;

GraphicsState state1 = g1.Save();
g2.Restore(state1); // state from the other Graphics

另外,多次恢复同一个状态安全吗?

Graphics g1 = ..;
Graphics g2 = ..;

GraphicsState state1 = g1.Save();
g2.Restore(state1);
g1.Restore(state1); // the same state used second time

我个人在我的代码中使用这两种技术都没有遇到任何问题,但我想确保它们是安全的/允许的。

我非常怀疑这是否能保证安全。正如 Graphics.Restore() 文档所解释的那样,当您调用 Save() 时,当前状态被压入堆栈(不是 堆栈……只是一些堆栈),然后当您调用 Restore(),状态将从堆栈中移除并应用于 Graphics 实例。

两个 Graphics 实例共享同一个堆栈是值得怀疑的。同样值得怀疑的是,从另一个 Graphics 实例的堆栈中恢复一个 Graphics 实例的状态是个好主意。

文档非常清楚地表明预期用途是让您平衡 Save()Restore() 调用,并将它们应用到同一个 Graphics 实例。


编辑:

为了完整起见,我继续更仔细地查看,事实上,虽然程序可能会或可能不会立即失败,但恢复从不同 Graphics 实例保存的状态绝对不是正确的用法:

  • 在托管代码中,文档引用的"stack"实际上是作为链表实现的。当您调用 Restore() 时,应用正在恢复的状态对象后,代码会在堆栈中搜索该对象;找到它后,它会处置该对象,以及在该对象之后保存但尚未恢复的所有其他状态对象。

如果找不到相应的对象,它只会发出 Debug.Fail() 消息。这样不会使您的代码崩溃,但很明显这不是理想的行为。

  • 为了真正恢复状态,托管代码调用非托管 GdipRestoreGraphics() 函数。从该调用(GDI+ Graphics.Restore() 函数)的已批准 OOP 包装器的文档中,引用 32 位整数 "state" 参数:“(由先前调用 Graphics::Save 方法返回此图形对象的)”[强调我的]。

这无疑使意图更加明确。此外,该文档页面还详细说明了正在维护的状态堆栈以及恢复状态时如何管理它。 GDI+ 堆栈类似于托管堆栈,实现方式相同。和托管堆栈一样,如果您恢复的状态不是针对那个 Graphics 实例,它将无法在堆栈中找到保存的状态。