C# 编程进阶详细讲解
1. C# 简介、VS 工具安装及使用
1.1 C# 语言概述
C#(发音为 C-Sharp)是微软开发的一种现代、面向对象的编程语言,它属于 .NET 平台的核心语言之一。C# 结合了 C++ 的强大功能和 Visual Basic 的易用性,语法简洁且类型安全。
C# 的主要特点:
- 面向对象:支持类、继承、多态等特性
- 类型安全:编译时进行严格的类型检查
- 组件导向:支持组件的定义、实现和使用
- 自动内存管理:通过垃圾回收机制自动管理内存
- 与 .NET 框架紧密集成:可以访问 .NET 提供的丰富类库
C# 的应用场景:
- 桌面应用程序开发
- Web 应用程序开发(ASP.NET)
- 移动应用开发(Xamarin)
- 游戏开发(Unity 引擎)
- 云服务和微服务
- 物联网应用
1.2 Visual Studio 工具安装
Visual Studio 是微软提供的集成开发环境(IDE),专门用于开发 C# 和其他 .NET 语言的应用程序。安装步骤如下:
- 访问 Visual Studio 官方下载页面
- 选择适合您需求的版本(社区版、专业版或企业版)
- 运行安装程序,选择所需的工作负载:
- 对于 C# 开发,建议选择 ".NET 桌面开发" 和 "ASP.NET 和 Web 开发 "
- 如果计划进行移动开发,还可以选择 "使用 .NET 的移动开发"
- 选择要安装的可选组件(如测试工具、版本控制等)
- 点击安装,等待安装完成
安装完成后,可以通过开始菜单启动 Visual Studio。首次启动时,系统会要求您选择开发设置和主题。
1.3 解决方案与项目模板
在 Visual Studio 中,解决方案(Solution)是项目的容器,一个解决方案可以包含多个相关的项目。项目(Project)则是应用程序的基本构建块,包含了源代码、资源文件和配置信息。
创建新项目的步骤:
- 启动 Visual Studio
- 选择 "创建新项目"
- 在搜索框中输入所需的项目模板类型(如 "控制台应用"、"Windows 窗体应用" 等)
- 选择适合的项目模板,点击 "下一步"
- 设置项目名称和位置,点击 "创建"
常见的 C# 项目模板:
- 控制台应用程序:用于创建命令行界面的应用程序
- Windows 窗体应用程序:用于创建 Windows 桌面应用程序
- WPF 应用程序:用于创建现代 Windows 桌面应用程序
- ASP.NET Web 应用程序:用于创建 Web 应用程序
- 类库:用于创建可重用的代码库
- Xamarin 应用程序:用于创建跨平台移动应用
1.4 编译过程及原理
C# 程序的编译过程涉及多个步骤:
-
源代码编译:C# 源代码(.cs 文件)被 C# 编译器(csc.exe)编译为中间语言(IL,Intermediate Language)代码,存储在程序集(.dll 或 .exe 文件)中。
-
程序集生成:编译后的 IL 代码与元数据(描述类型和成员信息)一起打包到程序集中。程序集是 .NET 应用程序的部署单元。
-
JIT 编译:当程序运行时,.NET 运行时(CLR,Common Language Runtime)使用即时编译器(JIT,Just-In-Time Compiler)将 IL 代码转换为机器码,以便 CPU 执行。
-
垃圾回收:CLR 负责管理内存,通过垃圾回收机制自动回收不再使用的对象所占用的内存。
C# 编译过程的优势:
- 跨平台性:IL 代码可以在任何支持 .NET 运行时的平台上执行
- 安全性:元数据提供了类型信息,增强了类型安全性
- 性能优化:JIT 编译可以根据运行时环境进行优化
2. 控制台程序基础
2.1 控制台程序结构
控制台程序是最简单的 C# 应用程序类型,它通过命令行界面与用户交互。一个基本的 C# 控制台程序结构如下:
csharp
using System;
namespace HelloWorld
{
class Program
{
static void Main(string[] args)
{
// 程序入口点
Console.WriteLine("Hello, World!");
Console.ReadLine(); // 等待用户输入,防止窗口立即关闭
}
}
}
程序结构说明:
using System;
:引入 System 命名空间,该命名空间包含了许多常用的类型和功能namespace HelloWorld
:定义命名空间,用于组织代码class Program
:定义一个名为 Program 的类static void Main(string[] args)
:程序的入口点方法,程序从这里开始执行Console.WriteLine()
:向控制台输出一行文本Console.ReadLine()
:从控制台读取一行输入
2.2 Main 方法详解
Main 方法是 C# 程序的入口点,它具有以下特点:
- 必须是静态方法(static)
- 返回类型可以是 void 或 int
- 可以接受一个字符串数组作为参数(string [] args),用于接收命令行参数
Main 方法的四种合法形式:
csharp
// 形式 1:无返回值,无参数
static void Main()
{
// 代码
}
// 形式 2:无返回值,带参数
static void Main(string[] args)
{
// 代码
}
// 形式 3:返回 int,无参数
static int Main()
{
// 代码
return 0; // 返回退出代码
}
// 形式 4:返回 int,带参数
static int Main(string[] args)
{
// 代码
return 0; // 返回退出代码
}
当 Main 方法返回 int 时,返回值通常用作程序的退出代码。退出代码 0 表示程序正常结束,非零值表示有错误发生。
2.3 Console 类使用
Console 类提供了与控制台进行交互的方法,主要包括输入输出功能。
常用的 Console 类方法:
csharp
// 输出方法
Console.WriteLine("Hello, World!"); // 输出一行文本并换行
Console.Write("Enter your name: "); // 输出文本但不换行
// 输入方法
string name = Console.ReadLine(); // 读取一行输入
int number = int.Parse(Console.ReadLine()); // 读取整数输入
// 颜色控制
Console.ForegroundColor = ConsoleColor.Red; // 设置文本颜色
Console.WriteLine("This text is red.");
Console.ResetColor(); // 恢复默认颜色
// 其他
Console.Beep(); // 发出蜂鸣声
Console.Clear(); // 清屏
2.4 注释与命名空间
注释
C# 支持三种类型的注释:
csharp
// 单行注释:用于注释单行代码
/*
多行注释:
用于注释多行代码
*/
/// <summary>
/// XML 注释:用于为类型和成员提供文档说明
/// 通常用于自动生成 API 文档
/// </summary>
public class MyClass
{
/// <summary>
/// 计算两个整数的和
/// </summary>
/// <param name="a">第一个整数</param>
/// <param name="b">第二个整数</param>
/// <returns>两个整数的和</returns>
public int Add(int a, int b)
{
return a + b;
}
}
命名空间
命名空间用于组织代码,避免命名冲突。可以使用 using
关键字引入其他命名空间,从而无需每次都使用完全限定名。
csharp
using System; // 引入 System 命名空间
using System.IO; // 引入 System.IO 命名空间
namespace MyNamespace
{
class Program
{
static void Main()
{
// 使用 System 命名空间中的 Console 类
Console.WriteLine("Hello, World!");
// 使用 System.IO 命名空间中的 File 类
File.WriteAllText("test.txt", "Hello, File!");
}
}
}
2.5 Debug 调试技巧
在开发过程中,调试是解决问题的重要手段。Visual Studio 提供了强大的调试功能:
-
设置断点:在代码行左侧单击,设置断点。程序执行到断点时会暂停,允许您检查变量和执行状态。
-
单步执行:
- F10:逐过程执行(跳过方法内部)
- F11:逐语句执行(进入方法内部)
- Shift+F11:跳出当前方法
-
检查变量:
- 鼠标悬停在变量上查看其值
- 使用 "局部变量" 窗口查看当前作用域内的所有变量
- 使用 "监视" 窗口跟踪特定变量的变化
-
调试输出:使用
System.Diagnostics.Debug.WriteLine()
输出调试信息 -
条件断点:右键单击断点,设置条件,只有当条件满足时断点才会触发
-
异常捕获:使用 "异常设置" 窗口指定要捕获的异常类型
调试示例:
csharp
using System;
namespace DebugExample
{
class Program
{
static void Main(string[] args)
{
int a = 10;
int b = 0;
// 设置断点在此行
int result = Divide(a, b);
Console.WriteLine($"Result: {result}");
}
static int Divide(int x, int y)
{
// 预期会发生除零异常
return x / y;
}
}
}
3. 数据类型与异常处理
3.1 值类型与引用类型
在 C# 中,数据类型分为两大类:值类型和引用类型。
值类型(Value Types)
值类型变量直接存储数据的值,它们分配在栈上(或作为字段嵌入在对象中)。值类型包括:
- 简单类型:整数(int, long, short 等)、浮点数(float, double)、布尔值(bool)、字符(char)
- 枚举类型(enum)
- 结构类型(struct)
- 可空值类型(Nullable<T>)
csharp
int num = 42; // 值类型,直接存储 42
bool isTrue = true;
char letter = 'A';
引用类型(Reference Types)
引用类型变量存储对数据的引用(内存地址),而不是数据本身。引用类型分配在堆上,通过垃圾回收自动管理内存。引用类型包括:
- 类(class)
- 接口(interface)
- 数组(array)
- 委托(delegate)
- 字符串(string)
csharp
string message = "Hello"; // 引用类型,存储对字符串对象的引用
int[] numbers = new int[5]; // 数组也是引用类型
值类型与引用类型的主要区别
特性 | 值类型 | 引用类型 |
---|---|---|
存储方式 | 直接存储值 | 存储对对象的引用 |
内存位置 | 栈或嵌入在对象中 | 堆 |
默认值 | 0, false, null 等 | null |
复制方式 | 复制值 | 复制引用 |
实例创建 | 无需使用 new 关键字 | 必须使用 new 关键字 |
继承 | 不支持继承(除了从 System.ValueType 继承) | 支持继承 |
3.2 可空类型
可空类型允许值类型变量存储 null 值,这在处理可能没有值的情况下非常有用。可空类型通过在值类型后加问号(?)来声明,实际上是 System.Nullable<T>
结构的简写。
csharp
int? nullableInt = null; // 可空 int 类型
DateTime? nullableDate = null; // 可空 DateTime 类型
// 使用可空类型
if (nullableInt.HasValue)
{
Console.WriteLine($"Value: {nullableInt.Value}");
}
else
{
Console.WriteLine("No value");
}
// 空合并运算符(??)
int value = nullableInt ?? 0; // 如果 nullableInt 为 null,则使用 0
3.3 变量与常量
变量
变量是存储数据的容器,必须先声明后使用。变量声明时需要指定类型,也可以使用 var
关键字让编译器自动推断类型。
csharp
// 显式类型声明
int age = 30;
string name = "John";
double salary = 5000.50;
// 隐式类型声明(使用 var)
var number = 100; // 编译器推断为 int
var message = "Hello"; // 编译器推断为 string
常量
常量是在编译时初始化且不能修改的值,使用 const
关键字声明。常量必须在声明时赋值,并且值必须是编译时常量表达式。
csharp
const double PI = 3.14159;
const string COMPANY_NAME = "ABC Inc.";
// 错误:常量必须在声明时赋值
// const int x;
// x = 10;
// 正确:编译时常量表达式
const int MAX_VALUE = 100 * 2;
3.4 C# 关键字与类型转换
C# 关键字
C# 有许多保留关键字,这些关键字不能用作标识符(如变量名、类名等),除非使用 @ 前缀。
常见的 C# 关键字:
- 数据类型:int, string, bool, double, char, class, struct, enum 等
- 控制流:if, else, switch, case, for, while, do, foreach 等
- 访问修饰符:public, private, protected, internal 等
- 其他:static, virtual, override, abstract, sealed, try, catch, finally 等
类型转换
类型转换是将一种数据类型转换为另一种数据类型的过程。C# 支持两种类型的转换:
- 隐式转换:编译器自动进行的转换,不会丢失数据。通常是从较小的类型转换为较大的类型。
csharp
int a = 10;
long b = a; // 隐式转换:int -> long
- 显式转换(强制转换):需要使用强制转换运算符
(type)
,可能会丢失数据。
csharp
double d = 3.14;
int i = (int)d; // 显式转换:double -> int,结果为 3
- 类型转换方法:使用
Convert
类或类型的Parse
/TryParse
方法。
csharp
string s = "123";
int num = int.Parse(s); // 字符串转整数
// 安全转换,避免异常
if (int.TryParse(s, out num))
{
Console.WriteLine($"Parsed: {num}");
}
else
{
Console.WriteLine("Invalid number");
}
// 使用 Convert 类
double d = 3.14;
int i = Convert.ToInt32(d); // 3
3.5 异常处理机制
异常是程序执行期间发生的错误。C# 提供了结构化的异常处理机制,使用 try-catch-finally
块来捕获和处理异常。
csharp
try
{
// 可能会抛出异常的代码
int result = Divide(10, 0); // 会抛出 DivideByZeroException
Console.WriteLine($"Result: {result}");
}
catch (DivideByZeroException ex)
{
// 处理特定类型的异常
Console.WriteLine($"Error: {ex.Message}");
}
catch (Exception ex)
{
// 处理其他类型的异常
Console.WriteLine($"General error: {ex.Message}");
}
finally
{
// 无论是否发生异常,都会执行的代码
Console.WriteLine("This code always executes.");
}
static int Divide(int x, int y)
{
if (y == 0)
{
throw new DivideByZeroException("除数不能为零"); // 抛出异常
}
return x / y;
}
自定义异常
可以通过继承 Exception
类来创建自定义异常:
csharp
public class CustomException : Exception
{
public CustomException() : base() { }
public CustomException(string message) : base(message) { }
public CustomException(string message, Exception innerException) : base(message, innerException) { }
}
使用 throw
重新抛出异常
在 catch 块中处理部分异常后,可以使用 throw
重新抛出异常:
csharp
try
{
// 代码
}
catch (Exception ex)
{
// 记录日志
Console.WriteLine($"Logging error: {ex.Message}");
throw; // 重新抛出原始异常
}
4. 运算符详解
4.1 赋值运算符
赋值运算符用于给变量赋值,最基本的是 =
,还有复合赋值运算符。
csharp
int a = 10; // 基本赋值
a += 5; // 复合赋值,等价于 a = a + 5
a -= 3; // 等价于 a = a - 3
a *= 2; // 等价于 a = a * 2
a /= 4; // 等价于 a = a / 4
a %= 3; // 等价于 a = a % 3
4.2 算数运算符
算数运算符用于执行基本的数学运算。
csharp
int a = 10, b = 3;
int sum = a + b; // 加法:13
int difference = a - b; // 减法:7
int product = a * b; // 乘法:30
int quotient = a / b; // 除法:3(整数除法)
int remainder = a % b; // 取余:1
// 自增和自减
int x = 5;
int y = ++x; // 先自增,再赋值,y = 6, x = 6
y = x++; // 先赋值,再自增,y = 6, x = 7
y = --x; // 先自减,再赋值,y = 5, x = 5
y = x--; // 先赋值,再自减,y = 5, x = 4
4.3 关系运算符
关系运算符用于比较两个值,返回布尔值。
csharp
int a = 10, b = 5;
bool result;
result = a > b; // 大于:true
result = a < b; // 小于:false
result = a >= b; // 大于等于:true
result = a <= b; // 小于等于:false
result = a == b; // 等于:false
result = a != b; // 不等于:true
4.4 逻辑运算符
逻辑运算符用于对布尔值进行逻辑操作。
csharp
bool x = true, y = false;
bool result;
result = x && y; // 逻辑与:false(两个都为 true 才为 true)
result = x || y; // 逻辑或:true(至少一个为 true 即为 true)
result = !x; // 逻辑非:false
result = x ^ y; // 逻辑异或:true(两个不同时为 true)
// 短路逻辑
bool a = false, b = true;
bool c = a && (b = false); // 由于 a 为 false,右侧表达式不会执行,b 仍为 true
4.5 位运算符
位运算符用于对整数类型的二进制位进行操作。
csharp
int a = 5; // 二进制:0101
int b = 3; // 二进制:0011
int result;
result = a & b; // 按位与:0001 (1)
result = a | b; // 按位或:0111 (7)
result = a ^ b; // 按位异或:0110 (6)
result = ~a; // 按位取反:1010 (-6,补码表示)
result = a << 2; // 左移两位:010100 (20)
result = a >> 1; // 右移一位:0010 (2)
4.6 三元运算符
三元运算符是一种简洁的条件表达式,语法为 condition ? value_if_true : value_if_false
。
csharp
int age = 18;
string message = age >= 18 ? "成年人" : "未成年人"; // "成年人"
// 嵌套三元运算符
int score = 85;
string grade = score >= 90 ? "A" :
(score >= 80 ? "B" :
(score >= 70 ? "C" :
(score >= 60 ? "D" : "F"))); // "B"
4.7 其他运算符
空条件运算符(?.)
用于在调用成员之前检查对象是否为 null,避免 NullReferenceException
。
csharp
string s = null;
int? length = s?.Length; // 如果 s 为 null,返回 null,否则返回 Length
空合并运算符(??)
用于提供默认值,当左侧操作数为 null 时返回右侧操作数。
csharp
string name = null;
string displayName = name ?? "未知"; // "未知"
类型检查运算符(is)
用于检查对象是否为特定类型。
csharp
object obj = "Hello";
bool isString = obj is string; // true
类型转换运算符(as)
尝试将对象转换为指定类型,如果转换失败则返回 null。
csharp
object obj = "Hello";
string s = obj as string; // 如果 obj 不是 string,返回 null
5. 数组与集合
5.1 数组基础与索引
数组是一种固定大小的、存储相同类型元素的连续内存块。数组可以通过索引访问,索引从 0 开始。
csharp
// 声明和初始化数组
int[] numbers = new int[5]; // 声明一个包含 5 个整数的数组
numbers[0] = 10; // 赋值给第一个元素
numbers[1] = 20;
numbers[2] = 30;
numbers[3] = 40;
numbers[4] = 50;
// 另一种初始化方式
string[] names = new string[] { "Alice", "Bob", "Charlie" };
// 简化语法
int[] scores = { 85, 90, 78, 92, 88 };
// 访问数组元素
int firstNumber = numbers[0]; // 10
string secondName = names[1]; // "Bob"
5.2 数组遍历与排序
遍历数组的常见方法:
csharp
int[] numbers = { 10, 20, 30, 40, 50 };
// 使用 for 循环
for (int i = 0; i < numbers.Length; i++)
{
Console.WriteLine(numbers[i]);
}
// 使用 foreach 循环
foreach (int number in numbers)
{
Console.WriteLine(number);
}
// 使用 Lambda 表达式(需要转换为 IEnumerable<int>)
Array.ForEach(numbers, n => Console.WriteLine(n));
数组排序:
csharp
int[] unsorted = { 5, 3, 8, 1, 2 };
Array.Sort(unsorted); // 升序排序:1, 2, 3, 5, 8
// 降序排序
Array.Sort(unsorted);
Array.Reverse(unsorted); // 8, 5, 3, 2, 1
// 自定义排序(降序)
Array.Sort(unsorted, (a, b) => b.CompareTo(a)); // 8, 5, 3, 2, 1
5.3 一维数组
一维数组是最简单的数组形式,上面的例子都是一维数组。
csharp
// 声明和初始化一维数组
int[] numbers = new int[5]; // 包含 5 个元素的整数数组
string[] names = { "Alice", "Bob", "Charlie" }; // 包含 3 个元素的字符串数组
5.4 多维数组
多维数组是指数组的元素也是数组,可以有二维、三维等。
csharp
// 二维数组
int[,] matrix = new int[3, 4]; // 3 行 4 列的二维数组
// 初始化二维数组
int[,] table = {
{ 1, 2, 3 },
{ 4, 5, 6 },
{ 7, 8, 9 }
};
// 访问二维数组元素
int value = table[1, 2]; // 第二行第三列的元素,值为 6
// 遍历二维数组
for (int i = 0; i < table.GetLength(0); i++) // 行数
{
for (int j = 0; j < table.GetLength(1); j++) // 列数
{
Console.Write(table[i, j] + " ");
}
Console.WriteLine();
}
5.5 交错数组
交错数组是数组的数组,每个子数组的长度可以不同。
csharp
// 声明交错数组
int[][] jaggedArray = new int[3][];
// 初始化每个子数组
jaggedArray[0] = new int[2]; // 第一个子数组有 2 个元素
jaggedArray[1] = new int[3]; // 第二个子数组有 3 个元素
jaggedArray[2] = new int[4]; // 第三个子数组有 4 个元素
// 赋值
jaggedArray[0][0] = 1;
jaggedArray[0][1] = 2;
jaggedArray[1][0] = 3;
jaggedArray[1][1] = 4;
jaggedArray[1][2] = 5;
// ...
// 另一种初始化方式
int[][] anotherJagged = new int[][] {
new int[] { 1, 2 },
new int[] { 3, 4, 5 },
new int[] { 6, 7, 8, 9 }
};
// 简化语法
int[][] simpleJagged = {
new int[] { 1, 2 },
new int[] { 3, 4, 5 },
new int[] { 6, 7, 8, 9 }
};
5.6 隐式类型化数组
隐式类型化数组使用 var
关键字声明,编译器会自动推断数组类型。
csharp
// 隐式类型化数组
var numbers = new[] { 10, 20, 30 }; // 推断为 int[]
var names = new[] { "Alice", "Bob", "Charlie" }; // 推断为 string[]
// 多维隐式类型化数组
var matrix = new[] {
new[] { 1, 2 },
new[] { 3, 4 }
}; // 推断为 int[][]
6. 面向对象编程基础
6.1 类与对象
类是对象的蓝图,定义了对象的属性和方法。对象是类的实例。
csharp
// 定义类
public class Person
{
// 字段
private string name;
private int age;
// 属性
public string Name
{
get { return name; }
set { name = value; }
}
public int Age
{
get { return age; }
set { age = value; }
}
// 方法
public void SayHello()
{
Console.WriteLine($"Hello, my name is {name} and I'm {age} years old.");
}
}
// 创建对象
Person person = new Person();
person.Name = "John";
person.Age = 30;
person.SayHello(); // 输出:Hello, my name is John and I'm 30 years old.
6.2 属性与方法
属性
属性是一种特殊的成员,提供对类的字段的访问,通常包含 get 和 set 访问器。
csharp
public class Rectangle
{
private double width;
private double height;
// 自动实现的属性
public double Width { get; set; }
public double Height { get; set; }
// 计算属性
public double Area
{
get { return Width * Height; }
}
// 带验证的属性
public double Length
{
get { return length; }
set
{
if (value < 0)
throw new ArgumentException("Length cannot be negative");
length = value;
}
}
}
方法
方法是类中定义的行为,包含一系列执行语句。
csharp
public class Calculator
{
// 静态方法
public static int Add(int a, int b)
{
return a + b;
}
// 实例方法
public int Subtract(int a, int b)
{
return a - b;
}
}
// 调用静态方法
int sum = Calculator.Add(10, 20);
// 调用实例方法
Calculator calc = new Calculator();
int difference = calc.Subtract(20, 10);
6.3 构造函数
构造函数是一种特殊的方法,用于初始化对象。构造函数的名称与类名相同,且没有返回类型。
csharp
public class Person
{
public string Name { get; set; }
public int Age { get; set; }
// 默认构造函数
public Person()
{
Name = "Unknown";
Age = 0;
}
// 带参数的构造函数
public Person(string name, int age)
{
Name = name;
Age = age;
}
}
// 创建对象
Person p1 = new Person(); // 使用默认构造函数
Person p2 = new Person("Alice", 25); // 使用带参数的构造函数
6.4 封装、继承与多态
封装
封装是将数据(字段)和操作数据的方法(属性和方法)绑定在一起,并隐藏对象的内部实现细节。通过访问修饰符(如 public、private)实现。
csharp
public class BankAccount
{
private decimal balance; // 私有字段,外部无法直接访问
public decimal Balance
{
get { return balance; }
private set { balance = value; } // 只能在类内部修改
}
public void Deposit(decimal amount)
{
if (amount > 0)
balance += amount;
}
public bool Withdraw(decimal amount)
{
if (amount <= balance)
{
balance -= amount;
return true;
}
return false;
}
}
继承
继承允许一个类(子类)继承另一个类(父类)的属性和方法,实现代码复用和层次化设计。
csharp
// 父类
public class Animal
{
public string Name { get; set; }
public Animal(string name)
{
Name = name;
}
public virtual void Speak()
{
Console.WriteLine($"{Name} makes a sound.");
}
}
// 子类
public class Dog : Animal
{
public Dog(string name) : base(name) { }
public override void Speak()
{
Console.WriteLine($"{Name} barks.");
}
}
// 使用继承
Animal animal = new Animal("Generic Animal");
animal.Speak(); // 输出:Generic Animal makes a sound.
Dog dog = new Dog("Buddy");
dog.Speak(); // 输出:Buddy barks.
多态
多态允许通过基类引用调用派生类的方法,实现运行时行为的动态绑定。
csharp
Animal animal1 = new Dog("Buddy");
Animal animal2 = new Cat("Whiskers");
animal1.Speak(); // 输出:Buddy barks.(动态绑定到 Dog 的 Speak 方法)
animal2.Speak(); // 输出:Whiskers meows.(动态绑定到 Cat 的 Speak 方法)
6.5 基类与子类
基类(父类)是被继承的类,子类(派生类)是继承基类的类。子类可以扩展基类的功能,也可以重写基类的方法。
csharp
// 基类
public class Vehicle
{
public string Brand { get; set; }
public virtual void Start()
{
Console.WriteLine("Vehicle started.");
}
}
// 子类
public class Car : Vehicle
{
public int NumberOfDoors { get; set; }
public override void Start()
{
Console.WriteLine($"Car {Brand} started.");
}
}
// 使用基类和子类
Vehicle vehicle = new Vehicle { Brand = "Generic Vehicle" };
vehicle.Start(); // 输出:Vehicle started.
Car car = new Car { Brand = "Toyota", NumberOfDoors = 4 };
car.Start(); // 输出:Car Toyota started.
7. 类的高级特性
7.1 部分类
部分类允许将一个类的定义分散到多个文件中,使用 partial
关键字声明。
csharp
// 文件1: Person.part1.cs
public partial class Person
{
public string Name { get; set; }
public int Age { get; set; }
public void SayHello()
{
Console.WriteLine($"Hello, my name is {Name}.");
}
}
// 文件2: Person.part2.cs
public partial class Person
{
public void SayGoodbye()
{
Console.WriteLine($"Goodbye from {Name}.");
}
}
// 使用部分类
Person person = new Person { Name = "John" };
person.SayHello(); // 输出:Hello, my name is John.
person.SayGoodbye(); // 输出:Goodbye from John.
7.2 静态类与静态方法
静态类只能包含静态成员,不能实例化。静态方法可以直接通过类名调用,无需创建对象。
csharp
// 静态类
public static class MathHelper
{
// 静态字段
public static readonly double PI = 3.14159;
// 静态方法
public static double CalculateCircleArea(double radius)
{
return PI * radius * radius;
}
}
// 使用静态类和静态方法
double area = MathHelper.CalculateCircleArea(5); // 直接通过类名调用
7.3 抽象类与抽象方法
抽象类不能被实例化,只能作为基类被继承。抽象方法没有实现体,必须在派生类中被重写。
csharp
// 抽象类
public abstract class Shape
{
// 抽象方法
public abstract double Area();
// 普通方法
public void Display()
{
Console.WriteLine($"Area: {Area()}");
}
}
// 具体实现类
public class Circle : Shape
{
public double Radius { get; set; }
public override double Area()
{
return Math.PI * Radius * Radius;
}
}
// 使用抽象类
Shape circle = new Circle { Radius = 5 };
circle.Display(); // 输出:Area: 78.5398163397448
7.4 密封类与密封方法
密封类使用 sealed
关键字声明,不能被继承。密封方法用于重写基类的虚方法,并禁止派生类进一步重写该方法。
csharp
// 基类
public class Animal
{
public virtual void Speak()
{
Console.WriteLine("Animal speaks.");
}
}
// 派生类,密封方法
public class Dog : Animal
{
public sealed override void Speak()
{
Console.WriteLine("Dog barks.");
}
}
// 错误:不能从密封类继承
// public class GoldenRetriever : Dog { }
7.5 虚方法与方法重写
虚方法使用 virtual
关键字声明,允许在派生类中重写。方法重写使用 override
关键字,提供方法的新实现。
csharp
// 基类
public class Shape
{
public virtual double Area()
{
return 0;
}
}
// 派生类
public class Rectangle : Shape
{
public double Width { get; set; }
public double Height { get; set; }
public override double Area()
{
return Width * Height;
}
}
// 使用虚方法和重写
Shape shape = new Rectangle { Width = 5, Height = 10 };
Console.WriteLine(shape.Area()); // 输出:50
7.6 方法重载
方法重载是指在同一个类中定义多个同名但参数不同的方法。
csharp
public class Calculator
{
public int Add(int a, int b)
{
return a + b;
}
public double Add(double a, double b)
{
return a + b;
}
public int Add(int a, int b, int c)
{
return a + b + c;
}
}
// 使用方法重载
Calculator calc = new Calculator();
int sum1 = calc.Add(1, 2); // 调用第一个 Add 方法
double sum2 = calc.Add(1.5, 2.5); // 调用第二个 Add 方法
int sum3 = calc.Add(1, 2, 3); // 调用第三个 Add 方法
7.7 方法参数传递(ref、out、in、params)
ref 参数
使用 ref
关键字传递参数,允许方法修改调用者提供的变量。参数必须在传递前初始化。
csharp
public void Swap(ref int a, ref int b)
{
int temp = a;
a = b;
b = temp;
}
// 使用 ref 参数
int x = 10, y = 20;
Swap(ref x, ref y); // x = 20, y = 10
out 参数
使用 out
关键字传递参数,要求方法必须在返回前为参数赋值。参数不需要在传递前初始化。
csharp
public void SplitName(string fullName, out string firstName, out string lastName)
{
string[] parts = fullName.Split(' ');
firstName = parts[0];
lastName = parts.Length > 1 ? parts[1] : "";
}
// 使用 out 参数
string fullName = "John Doe";
string first, last;
SplitName(fullName, out first, out last); // first = "John", last = "Doe"
in 参数
使用 in
关键字传递参数,确保方法不会修改参数的值,是只读的。
csharp
public void PrintValue(in int value)
{
// value = 100; // 错误:不能修改 in 参数
Console.WriteLine(value);
}
// 使用 in 参数
int number = 50;
PrintValue(in number);
params 参数
使用 params
关键字允许方法接受可变数量的参数,必须是方法的最后一个参数。
csharp
public int Sum(params int[] numbers)
{
int sum = 0;
foreach (int number in numbers)
{
sum += number;
}
return sum;
}
// 使用 params 参数
int total = Sum(1, 2, 3, 4, 5); // total = 15
8. 结构与枚举
8.1 结构类型
结构(struct)是一种值类型,通常用于表示轻量级对象,如点、矩形、日期等。
csharp
// 定义结构
public struct Point
{
public double X;
public double Y;
public Point(double x, double y)
{
X = x;
Y = y;
}
public double DistanceToOrigin()
{
return Math.Sqrt(X * X + Y * Y);
}
}
// 使用结构
Point p = new Point(3, 4);
double distance = p.DistanceToOrigin(); // 5
8.2 结构与类比较
特性 | 结构(struct) | 类(class) |
---|---|---|
类型 | 值类型 | 引用类型 |
内存位置 | 栈或嵌入在对象中 | 堆 |
继承 | 不能继承其他类型 | 可以继承基类和实现接口 |
实例化 | 无需使用 new 关键字 | 必须使用 new 关键字 |
默认构造函数 | 自动提供 | 必须显式定义 |
析构函数 | 不允许 | 允许 |
8.3 ref struct
ref struct
是一种特殊的结构,用于高性能场景,直接在栈上分配内存,不能在堆上分配。
csharp
// ref struct
public ref struct Span<T>
{
private readonly T[] _array;
private readonly int _start;
private readonly int _length;
public Span(T[] array, int start, int length)
{
_array = array;
_start = start;
_length = length;
}
public T this[int index]
{
get => _array[_start + index];
set => _array[_start + index] = value;
}
}
8.4 枚举类型
枚举(enum)是一种值类型,用于定义一组命名的常量。
csharp
// 定义枚举
public enum DayOfWeek
{
Monday,
Tuesday,
Wednesday,
Thursday,
Friday,
Saturday,
Sunday
}
// 使用枚举
DayOfWeek today = DayOfWeek.Monday;
Console.WriteLine(today); // 输出:Monday
// 枚举与整数的转换
int dayValue = (int)today; // dayValue = 0
DayOfWeek day = (DayOfWeek)2; // day = Wednesday
8.5 标记枚举
标记枚举使用 [Flags]
属性,允许将枚举值组合使用。
csharp
[Flags]
public enum Permissions
{
None = 0,
Read = 1,
Write = 2,
Execute = 4,
All = Read | Write | Execute
}
// 使用标记枚举
Permissions userPermissions = Permissions.Read | Permissions.Write;
if ((userPermissions & Permissions.Write) == Permissions.Write)
{
Console.WriteLine("用户有写入权限");
}
8.6 枚举类型转换
枚举与其他类型之间的转换:
csharp
// 枚举转字符串
string dayName = DayOfWeek.Monday.ToString(); // "Monday"
// 字符串转枚举
DayOfWeek day = (DayOfWeek)Enum.Parse(typeof(DayOfWeek), "Monday");
// 检查字符串是否是有效的枚举值
bool isValid = Enum.TryParse("Monday", out DayOfWeek result); // true
// 枚举与整数的转换
int value = (int)DayOfWeek.Tuesday; // 1
DayOfWeek day = (DayOfWeek)3; // Thursday
9. 高级编程特性
9.1 泛型
泛型允许创建参数化的类型和方法,提供类型安全而不损失性能。
csharp
// 泛型类
public class MyList<T>
{
private T[] items = new T[10];
private int count = 0;
public void Add(T item)
{
if (count < items.Length)
items[count++] = item;
}
public T Get(int index)
{
if (index < count)
return items[index];
throw new IndexOutOfRangeException();
}
}
// 使用泛型类
MyList<int> intList = new MyList<int>();
intList.Add(10);
int value = intList.Get(0);
MyList<string> stringList = new MyList<string>();
stringList.Add("Hello");
string text = stringList.Get(0);
9.2 逆变与协变
逆变和协变是泛型类型参数的两种变体,允许安全地进行类型转换。
协变(out)
协变允许使用比泛型参数指定的类型更派生的类型。
csharp
// 协变接口
public interface IReadOnlyCollection<out T>
{
int Count { get; }
T Get(int index);
}
// 使用协变
IReadOnlyCollection<object> objects = new List<string>(); // 合法,因为 string 是 object 的子类
逆变(in)
逆变允许使用比泛型参数指定的类型更基类的类型。
csharp
// 逆变接口
public interface IComparer<in T>
{
int Compare(T x, T y);
}
// 使用逆变
IComparer<object> objectComparer = new MyStringComparer(); // 合法,MyStringComparer 实现了 IComparer<string>
9.3 委托与事件
委托
委托是一种类型,它可以引用一个或多个方法。
csharp
// 定义委托
public delegate int MathOperation(int a, int b);
// 方法
public int Add(int a, int b) { return a + b; }
public int Subtract(int a, int b) { return a - b; }
// 使用委托
MathOperation operation = Add;
int result = operation(10, 5); // 调用 Add 方法
operation = Subtract;
result = operation(10, 5); // 调用 Subtract 方法
事件
事件是基于委托的一种机制,允许对象发布和订阅事件。
csharp
// 定义事件发布者
public class Button
{
// 定义事件
public event EventHandler Click;
// 触发事件的方法
public void OnClick()
{
Click?.Invoke(this, EventArgs.Empty);
}
}
// 定义事件订阅者
public class Form
{
private Button button = new Button();
public Form()
{
// 订阅事件
button.Click += Button_Click;
}
private void Button_Click(object sender, EventArgs e)
{
Console.WriteLine("按钮被点击了");
}
}
9.4 多线程编程
多线程允许程序同时执行多个任务,提高程序的响应性和性能。
csharp
using System.Threading;
public class Program
{
public static void Main()
{
// 创建线程
Thread thread = new Thread(DoWork);
thread.Start(); // 启动线程
// 主线程继续执行
Console.WriteLine("主线程继续执行...");
// 等待线程完成
thread.Join();
}
public static void DoWork()
{
for (int i = 0; i < 5; i++)
{
Console.WriteLine($"工作线程: {i}");
Thread.Sleep(100);
}
}
}
9.5 线程池
线程池管理一组工作线程,避免频繁创建和销毁线程的开销。
csharp
using System.Threading;
public class Program
{
public static void Main()
{
// 将工作项排队到线程池
ThreadPool.QueueUserWorkItem(DoWork);
Console.WriteLine("主线程继续执行...");
Thread.Sleep(2000); // 等待工作项完成
}
public static void DoWork(object state)
{
Console.WriteLine("线程池线程开始工作");
Thread.Sleep(1000);
Console.WriteLine("线程池线程完成工作");
}
}
9.6 Task 并行编程
Task
是 .NET 4.0 引入的高级并行编程模型,基于线程池。
csharp
using System.Threading.Tasks;
public class Program
{
public static async Task Main()
{
// 创建并启动任务
Task<int> task = Task.Run(() =>
{
Thread.Sleep(1000);
return 42;
});
// 等待任务完成并获取结果
int result = await task;
Console.WriteLine($"任务结果: {result}");
}
}
9.7 async/await 异步编程
async
和 await
是 C# 提供的语法糖,用于简化异步编程。
csharp
using System.Threading.Tasks;
public class Program
{
public static async Task Main()
{
Console.WriteLine("开始异步操作");
// 异步调用
string result = await DownloadDataAsync();
Console.WriteLine($"操作完成: {result}");
}
public static async Task<string> DownloadDataAsync()
{
// 模拟异步下载
await Task.Delay(2000);
return "下载完成";
}
}
9.8 任务并行库
任务并行库(TPL)提供了高级的并行编程功能,如并行循环和并行 LINQ。
csharp
using System.Threading.Tasks;
public class Program
{
public static void Main()
{
// 并行 for 循环
Parallel.For(0, 10, i =>
{
Console.WriteLine($"线程 {Task.CurrentId} 处理: {i}");
Thread.Sleep(100);
});
// 并行 foreach
string[] files = System.IO.Directory.GetFiles(@"C:\Temp");
Parallel.ForEach(files, file =>
{
Console.WriteLine($"处理文件: {file}");
});
}
}
10. 常用 API 与技术
10.1 字符串处理(string、StringBuilder)
string 类
csharp
string s1 = "Hello";
string s2 = "World";
string s3 = s1 + " " + s2; // "Hello World"
// 字符串操作
bool contains = s3.Contains("World"); // true
string upper = s3.ToUpper(); // "HELLO WORLD"
string[] parts = s3.Split(' '); // ["Hello", "World"]
string substring = s3.Substring(6); // "World"
StringBuilder 类
用于高效地构建字符串,避免频繁创建新的字符串对象。
csharp
StringBuilder sb = new StringBuilder();
sb.Append("Hello");
sb.Append(" ");
sb.Append("World");
string result = sb.ToString(); // "Hello World"
10.2 格式化与类型转换
字符串格式化
csharp
string name = "John";
int age = 30;
string message = string.Format("My name is {0} and I'm {1} years old.", name, age);
// 插值字符串(C# 6.0+)
string message2 = $"My name is {name} and I'm {age} years old.";
// 数字格式化
double number = 1234.5678;
string formatted = number.ToString("N2"); // "1,234.57"
类型转换
csharp
// 字符串转整数
int num = int.Parse("123");
bool success = int.TryParse("123", out int result);
// 其他类型转换
double d = 3.14;
int i = Convert.ToInt32(d); // 3
string s = Convert.ToString(42); // "42"
10.3 日期与时间处理
csharp
// 获取当前日期和时间
DateTime now = DateTime.Now;
DateTime today = DateTime.Today;
// 创建特定日期
DateTime birthday = new DateTime(1990, 5, 15);
// 日期计算
DateTime tomorrow = now.AddDays(1);
DateTime nextMonth = now.AddMonths(1);
TimeSpan duration = tomorrow - now; // 1 天
// 日期格式化
string formattedDate = now.ToString("yyyy-MM-dd");
string formattedTime = now.ToString("HH:mm:ss");
string formatted = now.ToString("f"); // "2023年5月1日 14:30"
// 时区转换
DateTime utcTime = DateTime.UtcNow;
DateTime localTime = utcTime.ToLocalTime();
10.4 数学运算
csharp
// 基本数学运算
int a = 10, b = 3;
int sum = a + b;
int difference = a - b;
int product = a * b;
double quotient = (double)a / b; // 3.3333...
// Math 类
double x = 3.14;
double abs = Math.Abs(-5); // 5
double ceiling = Math.Ceiling(x); // 4
double floor = Math.Floor(x); // 3
double round = Math.Round(x); // 3
double max = Math.Max(10, 20); // 20
double min = Math.Min(10, 20); // 10
double pow = Math.Pow(2, 3); // 8
double sqrt = Math.Sqrt(16); // 4
10.5 文件与流操作
文件操作
csharp
using System.IO;
// 写入文件
string content = "Hello, File!";
File.WriteAllText("test.txt", content);
// 读取文件
string readContent = File.ReadAllText("test.txt");
// 检查文件是否存在
bool exists = File.Exists("test.txt");
// 删除文件
if (exists)
File.Delete("test.txt");
流操作
csharp
using System.IO;
// 使用 StreamWriter 写入文件
using (StreamWriter writer = new StreamWriter("test.txt"))
{
writer.WriteLine("Line 1");
writer.WriteLine("Line 2");
}
// 使用 StreamReader 读取文件
using (StreamReader reader = new StreamReader("test.txt"))
{
string line;
while ((line = reader.ReadLine()) != null)
{
Console.WriteLine(line);
}
}
10.6 集合类(Array、ArrayList、List 等)
ArrayList
动态数组,可存储不同类型的对象,但不是类型安全的。
csharp
ArrayList list = new ArrayList();
list.Add(10);
list.Add("Hello");
list.Add(new Person());
int first = (int)list[0]; // 需要强制类型转换
List<T>
泛型集合,类型安全,性能更好。
csharp
List<int> numbers = new List<int>();
numbers.Add(10);
numbers.Add(20);
int first = numbers[0]; // 无需类型转换
// 遍历列表
foreach (int number in numbers)
{
Console.WriteLine(number);
}
// 列表操作
bool contains = numbers.Contains(10); // true
numbers.Remove(20);
int count = numbers.Count; // 1
Dictionary<TKey, TValue>
键值对集合,基于哈希表。
csharp
Dictionary<string, int> ages = new Dictionary<string, int>();
ages.Add("John", 30);
ages.Add("Alice", 25);
int johnAge = ages["John"]; // 30
// 检查键是否存在
if (ages.ContainsKey("Alice"))
{
int aliceAge = ages["Alice"];
}
// 遍历字典
foreach (KeyValuePair<string, int> pair in ages)
{
Console.WriteLine($"{pair.Key}: {pair.Value}");
}
10.7 线程与任务
见 9.4-9.7 节内容。
10.8 GUID 与加密
GUID
全局唯一标识符,用于生成唯一标识。
csharp
Guid guid = Guid.NewGuid();
string guidString = guid.ToString(); // 例如:"3f2504e0-4f89-11d3-9a0c-0305e82c3301"
MD5 加密
csharp
using System.Security.Cryptography;
using System.Text;
string input = "Hello, World!";
using (MD5 md5 = MD5.Create())
{
byte[] inputBytes = Encoding.UTF8.GetBytes(input);
byte[] hashBytes = md5.ComputeHash(inputBytes);
// 转换为十六进制字符串
StringBuilder sb = new StringBuilder();
for (int i = 0; i < hashBytes.Length; i++)
{
sb.Append(hashBytes[i].ToString("x2"));
}
string hash = sb.ToString(); // MD5 哈希值
}
10.9 序列化与反序列化
JSON 序列化
csharp
using System.Text.Json;
public class Person
{
public string Name { get; set; }
public int Age { get; set; }
}
// 序列化
Person person = new Person { Name = "John", Age = 30 };
string json = JsonSerializer.Serialize(person); // {"Name":"John","Age":30}
// 反序列化
Person deserialized = JsonSerializer.Deserialize<Person>(json);
10.10 特性(Attribute)
特性允许向程序元素(类、方法、属性等)添加元数据。
csharp
// 定义自定义特性
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public class AuthorAttribute : Attribute
{
public string Name { get; }
public string Version { get; }
public AuthorAttribute(string name, string version = "1.0")
{
Name = name;
Version = version;
}
}
// 使用特性
[Author("John Doe", "2.0")]
public class MyClass
{
[Author("Jane Smith")]
public void MyMethod()
{
// 方法实现
}
}
10.11 反射(Reflection)
反射允许在运行时检查和操作类型、方法、属性等。
csharp
// 获取类型信息
Type type = typeof(MyClass);
Console.WriteLine($"类型名称: {type.Name}");
// 获取特性信息
AuthorAttribute author = type.GetCustomAttribute<AuthorAttribute>();
if (author != null)
{
Console.WriteLine($"作者: {author.Name}, 版本: {author.Version}");
}
// 创建实例
object instance = Activator.CreateInstance(type);
// 调用方法
MethodInfo method = type.GetMethod("MyMethod");
method.Invoke(instance, null);
10.12 INI 文件读写
csharp
using System.IO;
public class IniFile
{
private Dictionary<string, Dictionary<string, string>> sections = new Dictionary<string, Dictionary<string, string>>();
private string filePath;
public IniFile(string filePath)
{
this.filePath = filePath;
Read();
}
private void Read()
{
if (!File.Exists(filePath))
return;
string currentSection = null;
foreach (string line in File.ReadAllLines(filePath))
{
string trimmed = line.Trim();
if (trimmed.StartsWith("[") && trimmed.EndsWith("]"))
{
currentSection = trimmed.Substring(1, trimmed.Length - 2);
sections[currentSection] = new Dictionary<string, string>();
}
else if (!string.IsNullOrEmpty(currentSection) && trimmed.Contains("="))
{
int index = trimmed.IndexOf("=");
string key = trimmed.Substring(0, index).Trim();
string value = trimmed.Substring(index + 1).Trim();
sections[currentSection][key] = value;
}
}
}
public string GetValue(string section, string key, string defaultValue = "")
{
if (sections.TryGetValue(section, out Dictionary<string, string> sectionData) &&
sectionData.TryGetValue(key, out string value))
{
return value;
}
return defaultValue;
}
public void SetValue(string section, string key, string value)
{
if (!sections.TryGetValue(section, out Dictionary<string, string> sectionData))
{
sectionData = new Dictionary<string, string>();
sections[section] = sectionData;
}
sectionData[key] = value;
Save();
}
private void Save()
{
using (StreamWriter writer = new StreamWriter(filePath))
{
foreach (var section in sections)
{
writer.WriteLine($"[{section.Key}]");
foreach (var keyValue in section.Value)
{
writer.WriteLine($"{keyValue.Key}={keyValue.Value}");
}
writer.WriteLine();
}
}
}
}
阶段项目:银行客户管理系统
项目需求分析
-
系统概述:
- 设计一个银行客户管理系统,用于管理客户信息和账户交易。
- 系统需要支持客户信息的增删改查,账户管理和交易记录。
-
功能需求:
- 客户管理:添加、修改、删除和查询客户信息
- 账户管理:为客户创建账户、查询账户余额
- 交易处理:存款、取款、转账
- 报表生成:客户列表、账户余额报表
-
非功能需求:
- 数据安全性:客户信息和交易数据需要安全存储
- 性能要求:系统响应时间在可接受范围内
- 易用性:界面友好,操作简单
系统架构设计
-
三层架构:
- 表示层(UI):负责与用户交互的界面
- 业务逻辑层(BLL):处理业务逻辑和规则
- 数据访问层(DAL):负责数据的存储和检索
-
技术选型:
- 开发语言:C#
- 数据库:SQL Server 或 MySQL
- 开发工具:Visual Studio
-
模块划分:
- 客户管理模块
- 账户管理模块
- 交易处理模块
- 报表生成模块
数据库设计
-
实体设计:
- 客户(Customer):客户 ID、姓名、地址、电话、电子邮件
- 账户(Account):账户 ID、客户 ID、账户类型、余额、开户日期
- 交易(Transaction):交易 ID、账户 ID、交易类型、金额、交易日期
-
表结构示例:
sql
CREATE TABLE Customers (
CustomerID INT PRIMARY KEY IDENTITY,
Name VARCHAR(100) NOT NULL,
Address VARCHAR(200),
Phone VARCHAR(20),
Email VARCHAR(100)
);
CREATE TABLE Accounts (
AccountID INT PRIMARY KEY IDENTITY,
CustomerID INT FOREIGN KEY REFERENCES Customers(CustomerID),
AccountType VARCHAR(50) NOT NULL,
Balance DECIMAL(18, 2) NOT NULL DEFAULT 0,
OpenDate DATETIME NOT NULL DEFAULT GETDATE()
);
CREATE TABLE Transactions (
TransactionID INT PRIMARY KEY IDENTITY,
AccountID INT FOREIGN KEY REFERENCES Accounts(AccountID),
TransactionType VARCHAR(50) NOT NULL,
Amount DECIMAL(18, 2) NOT NULL,
TransactionDate DATETIME NOT NULL DEFAULT GETDATE()
);
功能模块实现
-
客户管理模块:
- 添加客户:收集客户信息并保存到数据库
- 修改客户:根据客户 ID 更新客户信息
- 删除客户:根据客户 ID 删除客户及其关联账户
- 查询客户:根据条件查询客户信息
-
账户管理模块:
- 创建账户:为指定客户创建新账户
- 查询账户:根据账户 ID 或客户 ID 查询账户信息
- 账户列表:列出所有账户或指定客户的账户
-
交易处理模块:
- 存款:增加账户余额并记录交易
- 取款:减少账户余额并记录交易,检查余额是否充足
- 转账:从一个账户扣款并转入另一个账户,记录两笔交易
-
报表生成模块:
- 客户列表:生成所有客户的报表
- 账户余额报表:生成所有账户或指定客户的账户余额报表
- 交易历史:生成指定账户的交易历史记录
系统测试与优化
-
单元测试:
- 测试各个模块的功能是否正常工作
- 测试边界条件和异常情况的处理
-
集成测试:
- 测试各个模块之间的交互是否正常
- 测试数据在不同模块之间的流转是否正确
-
性能测试:
- 测试系统在高并发情况下的性能表现
- 找出性能瓶颈并进行优化
-
安全测试:
- 测试系统的安全性,包括数据加密、访问控制等
- 检查是否存在安全漏洞
-
用户反馈与优化:
- 收集用户反馈,对系统进行改进和优化
- 修复发现的问题,提高系统的稳定性和易用性