65.9K
CodeProject 正在变化。 阅读更多。
Home

如何开发年利计算器

starIcon
emptyStarIcon
starIcon
emptyStarIconemptyStarIconemptyStarIcon

1.50/5 (4投票s)

2010年1月22日

CPOL

5分钟阅读

viewsIcon

39391

downloadIcon

608

本文使用 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 字体清晰显示。下面是应用程序在未计算任何已赚利息时的样子:

Capture.JPG

这是四年利息的计算结果。读者请注意,这里显示的利息是复利。第一年 10,000 美元的本金,以 36% 的利率计算,赚取 36 美元,总计 10,036 美元。第二年的余额为 10,072.13 美元,比第一年多 36 美元 13 美分。复利会按 10,036 美元的本金计算 36% 的利息,而不仅仅是每年增加 36.00 美元。

Capture1.JPG

以下是将此应用程序放在一个文件中的代码,以便在 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
© . All rights reserved.