如何开发年利计算器






1.50/5 (4投票s)
本文使用 C# 开发一个年度计算工具。
引言
在学习 C# 这样的 .NET 语言时,你会很快发现有许多 API 可以简化某些操作——例如数学计算、文件 I/O、线程同步、网络通信等等——从而降低构建实际 Windows 应用程序的复杂性。本文将重点介绍如何使用框架类库中定义的某些数学 API 来构建一个实用的 Windows 窗体应用程序。但在开始构建此类应用程序之前,本文将首先通过示例代码描述其中一些 API、特殊字符和数字说明符。如果下载的应用程序没有实际用途,它也可以作为一个可以扩展的骨架应用程序,或者帮助用户创建一些有实际用途的类似应用。
一个用于将一个数字提升到另一个数字幂的基本数学 API 可以这样写:
public static class Math {
// method
public static extern double Pow (double x, double y);
...
}
现在,这是一个将数字 16 提升到 2次幂的非常基础的程序:
using System;
public class Application {
public static void Main() {
Console.WriteLine("Pow({0}, {1}) = {2}", 16, 2, Math.Pow(16, 2));
}
}
输出如下
Pow(16, 2) = 256
字符和转义序列
在 .NET Framework 中,字符始终由 16 位 Unicode 值表示。字符由 `System.Char` 结构(值类型)的实例表示,该结构提供了两个公共只读常量字段:`MinValue` 定义为 `\0`,`MaxValue` 定义为 `\uffff`。还有一组转义序列可用于表示难以直接表示的字符。例如,当你按下回车键时,光标会向下移动一行然后移到最左边。这被称为回车换行符,分别称为 0x0D 和 0x0A。因此,当你构建一个将执行操作并将结果显示在多行文本框中的 Windows 应用程序时,这些转义序列在字符串格式化和换行方面发挥着作用。
- \' \u0027 (39) 单引号
- \" \u0022 (34) 双引号
- \\ \u005C (92) 反斜杠
- \0 \u0000 (0) 空字符
- \a \u0007 (7) 响铃
- \b \u0008 (8) 退格
- \t \u0009 (9) 制表符
- \v \u000B (11) 垂直制表符
- \f \u000C (12) 换页符
- \n \u000A (10) 换行符
- \r \u000D (13) 回车符
下面是一段代码片段,展示了其中一些转义序列的用法:
using System;
public class Program {
public static void Main() {
Console.WriteLine("Alert \\a: {0} ({1})", '\a', (int)'\a');
Console.WriteLine("Backspace \\b: {0} ({1})", '\b', (int)'\b');
Console.WriteLine("Horizontal tab \\t: {0} ({1})", '\t', (int)'\t');
Console.WriteLine("Newline \\r: {0} ({1})", '\r', (int)'\r');
Console.WriteLine("Vertical quote \\v: {0} ({1})", '\v', (int)'\v');
Console.WriteLine("Form feed \\f: {0} ({1})", '\f', (int)'\f');
Console.WriteLine("Carriage return \\r: {0} ({1})", '\r', (int)'\r');
}
}
输出如下:
Alert \a: (7)
Backspace \b: (8)
Horizontal tab \t: (9)
(13)ne \r:
Vertical quote \v: ♂‚ (11)
Form feed \f: ♀ (12)
(13)age return \r:
那么,展示一个数字的幂运算和 .NET Framework 字符的技术细节有什么意义呢?它们将在我们构建应用程序时发挥关键作用。该应用程序需要一个 Windows 窗体,其中包含三个 `Label`(标签)控件、两个用于用户输入的普通 `TextBox`(文本框)控件、一个 `NumericUpDown`(数值增减)控件,以及一个带有垂直滚动条的第三个多行文本框。`NumericUpDown` 控件与 `DomainUpDown` 控件非常相似,只是其内容限制为数字。最后,一个 `Button`(按钮)控件将接收两个用户输入字段——本金和利息,并计算出赚取利息后的年度账户余额。`NumericUpDown` 控件每次递增一:所以如果你从 1 点击到 2,你将在多行文本框的第二行获得输出,显示赚取的利息。`NumericUpDown` 控件的 `Minimum` 属性设置为 1,`Maximum` 属性设置为 10。其 `Increment` 属性设置为 1,而 `ReadOnly` 属性设置为 `true
`。所有 `Label` 控件的 `AutoSize` 属性都设置为 `false
`,以便使用 16 磅的 Times New Roman 字体清晰显示。下面是应用程序在未计算任何已赚利息时的样子:
这是四年利息的计算结果。读者请注意,这里显示的利息是复利。第一年 10,000 美元的本金,以 36% 的利率计算,赚取 36 美元,总计 10,036 美元。第二年的余额为 10,072.13 美元,比第一年多 36 美元 13 美分。复利会按 10,036 美元的本金计算 36% 的利息,而不仅仅是每年增加 36.00 美元。
以下是将此应用程序放在一个文件中的代码,以便在 DOS 提示符下进行编译。在目录 "C:\Windows\Microsoft.NET\Framework\v2.0.50727" 中,键入 'type con > Thefile.cs'。光标将移到空白屏幕,没有提示符。将代码复制并粘贴到空白的 DOS 窗口中,然后使用 '/target:winexe' 开关编译代码:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
public partial class Form1 : Form
{
private System.Windows.Forms.Button calculateButton;
private System.Windows.Forms.TextBox principalTextBox;
private System.Windows.Forms.Label label1;
private System.Windows.Forms.TextBox interestTextBox;
private System.Windows.Forms.Label label2;
private System.Windows.Forms.NumericUpDown yearUpDown;
private System.Windows.Forms.TextBox displayTextBox;
private System.Windows.Forms.VScrollBar vScrollBar1;
private System.Windows.Forms.Label label3;
public Form1()
{
InitializeComponent();
}
private void InitializeComponent() {
this.calculateButton = new System.Windows.Forms.Button();
this.principalTextBox = new System.Windows.Forms.TextBox();
this.label1 = new System.Windows.Forms.Label();
this.interestTextBox = new System.Windows.Forms.TextBox();
this.label2 = new System.Windows.Forms.Label();
this.yearUpDown = new System.Windows.Forms.NumericUpDown();
this.displayTextBox = new System.Windows.Forms.TextBox();
this.vScrollBar1 = new System.Windows.Forms.VScrollBar();
this.label3 = new System.Windows.Forms.Label();
this.SuspendLayout();
//
// calculateButton
//
this.calculateButton.Font =
new System.Drawing.Font("Times New Roman", 14.25F,
System.Drawing.FontStyle.Bold,
System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.calculateButton.Location = new System.Drawing.Point(310, 30);
this.calculateButton.Name = "calculateButton";
this.calculateButton.Size = new System.Drawing.Size(103, 33);
this.calculateButton.TabIndex = 0;
this.calculateButton.Text = "Calculate";
this.calculateButton.UseVisualStyleBackColor = true;
this.calculateButton.Click +=
new System.EventHandler(this.calculateButton_Click);
//
// principalTextBox
//
this.principalTextBox.Location = new System.Drawing.Point(152, 30);
this.principalTextBox.Name = "principalTextBox";
this.principalTextBox.Size = new System.Drawing.Size(133, 20);
this.principalTextBox.TabIndex = 1;
//
// label1
//
this.label1.Font =
new System.Drawing.Font("Times New Roman", 15.75F,
((System.Drawing.FontStyle)((System.Drawing.FontStyle.Bold |
System.Drawing.FontStyle.Italic))),
System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.label1.Location = new System.Drawing.Point(14, 33);
this.label1.Name = "label1";
this.label1.Size = new System.Drawing.Size(100, 23);
this.label1.TabIndex = 2;
this.label1.Text = "Principal";
//
// interestTextBox
//
this.interestTextBox.Location = new System.Drawing.Point(152, 105);
this.interestTextBox.Name = "interestTextBox";
this.interestTextBox.Size = new System.Drawing.Size(133, 20);
this.interestTextBox.TabIndex = 3;
//
// label2
//
this.label2.Font =
new System.Drawing.Font("Times New Roman",
15.75F, System.Drawing.FontStyle.Bold,
System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.label2.Location = new System.Drawing.Point(18, 105);
this.label2.Name = "label2";
this.label2.Size = new System.Drawing.Size(100, 23);
this.label2.TabIndex = 4;
this.label2.Text = "Interest";
//
// yearUpDown
//
this.yearUpDown.Location = new System.Drawing.Point(267, 178);
this.yearUpDown.Maximum =
new decimal(new int[] {
10,
0,
0,
0});
this.yearUpDown.Minimum =
new decimal(new int[] {
1,
0,
0,
0});
this.yearUpDown.Name = "yearUpDown";
this.yearUpDown.ReadOnly = true;
this.yearUpDown.Size = new System.Drawing.Size(37, 20);
this.yearUpDown.TabIndex = 5;
this.yearUpDown.Value =
new decimal(new int[] {
1,
0,
0,
0});
//
// displayTextBox
//
this.displayTextBox.Location = new System.Drawing.Point(70, 298);
this.displayTextBox.Multiline = true;
this.displayTextBox.Name = "displayTextBox";
this.displayTextBox.Size = new System.Drawing.Size(300, 120);
this.displayTextBox.TabIndex = 6;
//
// vScrollBar1
//
this.vScrollBar1.Location = new System.Drawing.Point(353, 298);
this.vScrollBar1.Name = "vScrollBar1";
this.vScrollBar1.Size = new System.Drawing.Size(17, 120);
this.vScrollBar1.TabIndex = 7;
//
// label3
//
this.label3.Font =
new System.Drawing.Font("Times New Roman", 12F,
System.Drawing.FontStyle.Bold,
System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.label3.Location = new System.Drawing.Point(70, 238);
this.label3.Name = "label3";
this.label3.Size = new System.Drawing.Size(189, 23);
this.label3.TabIndex = 8;
this.label3.Text = "Your Account Balance is:";
//
// Form1
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.BackColor =
System.Drawing.Color.FromArgb(((int)(((byte)(0)))),
((int)(((byte)(192)))), ((int)(((byte)(0)))));
this.ClientSize = new System.Drawing.Size(427, 451);
this.Controls.Add(this.label3);
this.Controls.Add(this.vScrollBar1);
this.Controls.Add(this.displayTextBox);
this.Controls.Add(this.yearUpDown);
this.Controls.Add(this.label2);
this.Controls.Add(this.interestTextBox);
this.Controls.Add(this.label1);
this.Controls.Add(this.principalTextBox);
this.Controls.Add(this.calculateButton);
this.Name = "Form1";
this.Text = "Form1";
this.ResumeLayout(false);
this.PerformLayout();
}
[System.STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
private void calculateButton_Click(object sender, EventArgs e)
{
decimal principal;
double rate;
int year;
decimal amount;
string output;
principal = Convert.ToDecimal(principalTextBox.Text);
rate = Convert.ToDouble(interestTextBox.Text);
year = Convert.ToInt32(yearUpDown.Value);
output = "year\tAmount on Deposit\r\n";
for (int yearCounter = 1; yearCounter <= year; yearCounter++)
{
amount = principal * ( ( decimal)
Math.Pow(( 1 + rate / 100), yearCounter));
output += (yearCounter + "\t" +
string.Format( "{0:C}", amount) +
"\r\n" );
}
displayTextBox.Text = output;
}
}
注意 `Button` 控件的事件处理程序。我们首先声明了由前两个 `Label` 控件和计算所需的其他变量表示的数据类型。输出被视为 `string
` 类型,以便使用制表符、回车符和换行符转义序列来格式化计算。分隔符 "{0:C}" 代表货币。因此,这些变量被转换为数字数据类型,然后将前两个 `TextBox` 控件和 `NumericUpDown` 控件的 `Name`(属性)作为参数传递。然后,它们在一个 `for
` 循环中使用,以迭代计算的年数,每年递增一。之后,使用 Math Power API 计算 `string
` 数据类型 "amount",最后将结果输出到多行文本框中,该文本框的 `Name` 已设置为输出。
.NET Framework 使用 16 位 Unicode 编码方案是为了简化全球开发带来的复杂性。`C` 是一个说明符,它使用特定于区域性的货币属性(如符号(货币、分隔符)和有效数字位数)来格式化字符串。
参考文献
- 《Professional .NET Framework 2.0》作者:Joe Duffy
- 《CLR via C#》作者:Jeffrey Richter