使用 CBOR 库创建计算器应用程序





4.00/5 (3投票s)
详细介绍如何借助我的 CBOR 库实现计算器程序
本页面介绍了如何使用我的 C# CBOR 库实现一个计算器程序。(CBOR 是 Concise Binary Object Representation 的缩写。)本页面展示了同一程序的 Windows Forms 和 Windows Presentation Foundation (WPF) 版本,演示了我的库在这两种程序中都能很好地工作。
虽然它看起来相对简单,但计算器程序演示了该库的两个特性
- 它支持任意精度算术。
- 读写 CBOR 数据。
这两个特性将依次讨论。
任意精度算术
当然,程序的主要目的是进行计算。此计算器程序由我的 CBOR 库对任意精度十进制算术的支持提供支持。虽然 `double`(一种 64 位二进制浮点数类型)适用于大多数情况,但由于使用二进制而不是十进制系统,它有时会提供不直观的结果。
CBOR 库支持任意精度数字(二进制和十进制),主要是因为 CBOR 定义中(RFC)的几个标签(其中两个定义在定义 CBOR 的 RFC 中)支持这类数字,并且在这些数字上进行算术和其他有用操作被认为很有用。
`CalculatorState` 类存储计算器的当前状态,例如当前显示的数字以及当前执行的操作。以下列出了一些 `CalculatorState` 的方法。
public CalculatorState(int maxDigits);
public string Text { get; }
public bool DotButton();
public bool PlusMinusButton();
public bool EqualsButton();
public bool DigitButton();
`CalculatorState` 构造函数使用 `maxDigits` 的数字精度初始化计算器状态。这意味着显示屏上最多会显示这么多位数。计算器程序将其设置为 18(在 `MainForm` 构造函数中),但这可以设置为任何所需的数字(只要大于等于 1)。 `CalculatorState` 使用 CBOR 库的 `ExtendedDecimal` 类来存储数字并对其进行操作,并使用该库的 `PrecisionContext` 类将其精度限制为给定的位数。
`Text` 属性获取一个显示计算器当前显示内容的字符串。每次按下按钮并使用该字符串更新顶部的文本框时,都会检索此字符串。
该类还包含几个以 `Button` 结尾的方法,例如 `DotButton` 和 `DigitButton`。这些方法会更改计算器状态,使其行为非常类似于普通计算器的相应按钮。例如,`DotButton` 方法会在当前输入不包含小数点的情况下添加一个小数点;`EqualsButton` 方法执行算术运算,依此类推。
抽象
`CalculatorState` 类作为一种抽象存在;它将计算器逻辑与计算器用户界面分开,并且可以被认为是“模型-视图-控制器”设计模式中的“模型”部分。由于这种抽象,该类可以用于 Windows Forms 程序以外的其他程序,这些程序需要计算器的功能。
第二个抽象是“控制器”:“ `CalculatorController` 类使用程序主窗口的接口(`IWindowInfo`)并包含与 `CalculatorState` 类类似的方法,只不过它更像一个控制器而不是数据模型(每个窗体实现都调用 `CalculatorController` 而不是 `CalculatorState`。)计算器的 Windows Forms 和 WPF 版本具有不同的 `IWindowInfo` 实现。
存储应用程序设置
CBOR 的紧凑数据格式非常适合存储用户设置等内容。
计算器程序对此进行了演示;当程序退出时,它会获取窗口的当前位置和大小,将它们存储在用户设置对象中,并将用户设置对象转换为 CBOR 文件。
`ProgramConfig` 类用于存储用户设置。它具有这些方法:
public ProgramConfig(string configName);
public ProgramConfig SetObject(string name, object obj);
public string GetString(string name);
public int GetInt32OrDefault(string name, int defaultValue);
public double GetDoubleOrDefault(string name, double defaultValue);
public double GetDouble(string name);
如果程序安装在可能为只读位置(例如 Program Files 文件夹)中,计算器会将用户设置存储在每个用户的应用程序存储中。这可以通过 .NET 4 支持的 `System.IO.IsolatedStorage` 命名空间实现。(Windows 应用商店应用使用单独的应用程序存储概念,这在演示中不受支持,但由于实现的性质,可以轻松添加,如下所述。)
加载和保存
`ProgramConfig` 构造函数从每个用户的存储中打开一个命名文件(带有“.cbor”扩展名,因为它加载和保存 CBOR 文件),并在文件不存在(通常是程序首次运行时)或文件包含无效数据时生成空白用户数据。计算器在窗体加载时创建 `ProgramConfig` 构造函数(参见 *MainForm.cs*)。
private void MainForm_Load(object sender, EventArgs e) {
// Initialize config here, rather than in the constructor;
// the system may automatically move the window in between
this.config = this.InitializeConfig();
}
private ProgramConfig InitializeConfig() {
return new ProgramConfig("config").FormPosFromConfig(this);
}
首次运行时,`ProgramConfig` 会被生成并填充为窗体首次加载时的默认窗口位置值(由于 `FormPosFromConfig` 方法)。
程序关闭时,它会检索窗口的当前位置并将用户数据保存到每个用户的存储中。
private void MainForm_FormClosing(object sender, FormClosingEventArgs e) {
this.SaveConfig();
}
private void SaveConfig() {
if (this.config != null) {
this.config.FormPosToConfig(this).Save();
}
}
因此,如果用户再次运行程序,上次使用的窗口位置和大小将被恢复。
也可以在程序运行时保存用户设置(例如,在用户更改程序设置后)或在运行时访问用户设置,但这些可能性目前未在计算器程序中演示。
读取和写入设置
`ProgramConfig` 类创建一个 CBOR 键值映射。它的三个方法 `GetString`、`GetInt32OrDefault` 和 `GetDouble` 通过键检索值。 `SetObject` 方法将多种类型的对象(不仅限于字符串和数字)转换为适合 CBOR 键值映射的格式。
不过,计算器演示仅使用数字(用于窗口位置和大小),因此它调用 `GetDoubleOrDefault` 并在生成时为每个参数设置当前窗口位置和大小的默认值。(如果键不存在或现有值类型错误或无法转换,`GetDoubleOrDefault` 会使用默认值。)
更具体地说,计算器演示在 `ProgramConfig` 映射中使用以下键:
- `"x"` - 计算器窗口左上角的 X 坐标。
- `"y"` - 窗口左上角的 Y 坐标。
- `"width"` - 窗口左上角的宽度(以像素为单位)。
- `"height"` - 窗口左上角的高度(以像素为单位)。
目前 `ProgramConfig` 只能“获取”三种数据:字符串、`double` 和 32 位无符号整数(`int`)。这通常足以满足大多数用户设置(例如,布尔值——`true` 或 `false`——可以使用整数或字符串表示),但当然,CBOR 可以存储许多其他数据类型,例如嵌套数组、嵌套映射、字节序列、未定义值以及任意精度的数字。但对于用户设置,特别是对于计算器演示,字符串、`double` 和 `int` 这三种数据类型通常就足够了。
ProgramConfig 实现
我使 `ProgramConfig` 类足够通用,可以用于许多不同类型的程序;例如,它也用于我的另一个演示程序,该程序将 JSON 转换为 CBOR 并反之。该程序也以与计算器演示相同的方式保存上次已知的窗口位置和大小。 `ProgramConfig` 的某些“方法”被设计为扩展方法并放在单独的类 `FormConfig` 中。(FormConfig 接受实现 IWindowInfo 接口的抽象对象,并检索和设置窗口位置。Windows Forms 和 WPF 版本有单独的 IWindowInfo 实现。)
然而,虽然 `ProgramConfig` 非常通用,但它依赖于隔离存储,而隔离存储不幸的是在 Windows 应用商店应用中不受支持,后者使用非常不同的概念来处理每个用户的存储。(隔离存储可以在 Windows Forms 和 WPF 应用中使用,如本演示中所述。)这就是为什么 ProgramConfig 包含一个名为 `IsolatedStream` 的嵌套类,该类旨在包装每个用户存储实现的详细信息。
如果需要 Windows 应用商店应用的每个用户存储版本,则可以更新 `IsolatedStream` 以提供或调用特定于 Windows 应用商店的每个用户存储实现。此处未执行此操作,因为主要目的是演示我的 CBOR 库的特性。
我应该注意的是,CBOR 库本身不包含直接读写文件的任何方法;它而是从流中读取和写入数据(例如,CBOR 数据的 `Read` 和 `WriteTo` 方法,以及 JavaScript Object Notation 的 `ReadJSON` 和 `WriteJSONTo` 方法)。
结论
这就是我关于如何使用计算器程序我的 C# CBOR 库实现的讨论的总结,包括其功能如何融入程序的结构以及有关在应用程序中存储每个用户设置的技巧。