2

我正在用 C# 编写一个需要支持撤消/重做的程序。为此,我选择了命令模式;tldr,操作文档状态的每个操作都必须由一个 Command 对象执行,该对象知道文档的先前状态以及需要进行的更改,并且能够自行执行/撤消。

它适用于简单的操作,但我现在有一个操作会同时影响文档的多个部分。同样,Command 对象必须足够聪明,知道它需要保留的所有旧状态,以防它需要撤消。

问题是如果有人试图直接调用接口,使用公共接口暴露所有状态有可能被滥用,这可能导致状态损坏。我的直觉告诉我这样做的最面向对象的方法是公开专门的 Command 类——而不是让您直接操作文档的状态,您所能做的就是要求文档创建一个可以访问其的 Command 对象内部状态,并保证足够了解以正确支持撤消/重做。

不幸的是,C# 不支持朋友的概念,所以我无法创建一个可以访问文档内部的 Command 类。有没有办法将文档类的私有成员暴露给另一个类,或者有没有其他方法可以做我需要的事情而不必暴露很多文档内部?

4

4 回答 4

2

这取决于,如果您正在部署一个库,您的 Document 可以声明“内部”方法以与其内部状态进行交互,这些方法将由您的 Command 类使用,内部方法仅限于它们编译的程序集。

或者您可以将一个私有类嵌套到您的 Document 中,这样它就可以访问 Document 的内部状态并向其公开一个公共接口,然后您的 Document 将创建一个被该接口隐藏的命令类。

于 2011-12-25T19:56:35.990 回答
2

首先,C# 具有internal声明“朋友”可访问性的关键字,它允许从整个程序集中进行公共访问。

其次,“朋友”可访问性可以扩展到具有程序集属性的第二个程序集InternalsVisibleTo,这样您就可以为您的命令创建第二个项目,而文档的内部结构将保持在内部。

或者,如果您的命令对象嵌套在文档类中,那么它们将可以访问其所有私有成员。

最后,复杂的命令也可以在进行更改之前简单地克隆文档。这是一个简单的解决方案,尽管不是很优化。

于 2011-12-25T20:11:32.427 回答
0

Type.GetField(string, BindingFlags.Private)您始终可以通过反射(和朋友)访问字段和属性,无论是否私有。

也许在类(或字段/属性)上使用自定义属性来自动化为每个命令获取足够状态的过程?

于 2011-12-25T19:49:14.703 回答
0

您可以使用两个虚拟命令来标记多步操作的开始和结束,而不是让命令在文档的不同位置进行更改。让我们称它们为 BeginCommand 和 EndCommand。首先,将 BeginCommand 推送到 undo-stack,然后将不同的步骤作为单个命令执行,每个命令仅在文档的一个位置进行更改。当然,您也将它们推送到撤消堆栈上。最后,将 EndCommand 推送到撤消堆栈上。

撤消时,检查从撤消堆栈中弹出的命令是否是 EndCommand。如果是,则继续撤消直到到达 BeginCommand。

这会将多步命令变成将工作委派给其他命令的宏命令。该宏命令本身不会被压入撤消堆栈。

于 2011-12-25T22:44:43.577 回答