引言:为什么选择.NET作为你的编程起点
在当今快速发展的技术世界中,选择一个合适的编程平台作为职业生涯的起点至关重要。.NET(通常读作”dot net”)是由微软开发的一个免费、开源的开发者平台,它以其强大的功能、跨平台能力和丰富的生态系统,成为了无数开发者的首选。无论你是完全的编程新手,还是希望从其他技术栈转型,.NET都提供了一条清晰、系统的学习路径。
.NET平台的核心优势在于其多功能性。使用.NET,你可以构建各种类型的应用程序:从传统的桌面应用(Windows Forms、WPF),到现代的Web应用(ASP.NET Core),再到移动应用(通过Xamarin或MAUI),甚至是云原生微服务和游戏开发(Unity引擎的一部分)。更重要的是,随着.NET Core的发布和后续的.NET 5/6/7/8的演进,.NET已经完全实现了跨平台,可以在Windows、Linux和macOS上无缝运行。
对于初学者来说,.NET生态系统提供了强大的集成开发环境(IDE)——Visual Studio和Visual Studio Code,以及优秀的调试工具和丰富的类库,这些都极大地降低了学习门槛。同时,C#作为.NET的主语言,是一门现代、优雅且功能强大的编程语言,它吸收了多种语言的优点,既有面向对象的严谨性,又有函数式编程的灵活性。
本文将带你从零基础开始,系统地学习.NET的核心技术,通过实际的代码示例和项目实践,帮助你掌握从基础语法到高级特性的全套知识体系,最终具备实际项目开发能力,为开启编程职业生涯打下坚实的基础。
第一章:搭建开发环境与第一个.NET程序
1.1 安装必要的开发工具
在开始编写.NET代码之前,我们需要先搭建开发环境。对于初学者,推荐安装以下工具:
.NET SDK:这是.NET开发的核心,包含了编译器、运行时和命令行工具。
- 访问 https://dotnet.microsoft.com/download
- 下载适合你操作系统的最新版本(推荐.NET 8或更高版本)
- 按照安装向导完成安装
开发IDE:
- Visual Studio 2022 Community版(Windows用户):功能强大的免费IDE,提供优秀的调试和智能提示功能
- Visual Studio Code(跨平台):轻量级编辑器,配合C#扩展插件也能提供良好的开发体验
1.2 创建你的第一个.NET控制台应用
让我们通过创建一个经典的”Hello World”程序来验证环境是否配置成功。我们将使用命令行方式创建项目,这有助于理解.NET的项目结构。
打开命令提示符(Windows)或终端(macOS/Linux),执行以下命令:
# 创建一个新的控制台应用项目
dotnet new console -n HelloWorld
# 进入项目目录
cd HelloWorld
# 查看项目结构
dir # Windows
ls # macOS/Linux
执行上述命令后,你会看到类似以下的项目结构:
HelloWorld/
├── HelloWorld.csproj # 项目文件,定义项目配置和依赖
├── Program.cs # 主程序文件
└── obj/ # 编译中间文件目录(自动生成)
1.3 编写和运行代码
用文本编辑器或IDE打开Program.cs文件,你会看到类似以下的代码:
// 这是你的第一个.NET程序
Console.WriteLine("Hello, World!");
让我们稍微扩展一下这个程序,添加一些交互功能:
// 显示欢迎信息
Console.WriteLine("欢迎来到.NET编程世界!");
// 获取用户输入
Console.Write("请输入你的名字:");
string? name = Console.ReadLine();
// 显示个性化问候
Console.WriteLine($"你好,{name}!很高兴认识你。");
// 等待用户按任意键退出
Console.WriteLine("\n按任意键退出...");
Console.ReadKey();
要运行这个程序,在项目目录下执行:
dotnet run
你将会看到程序输出并等待你输入名字。这个简单的程序演示了.NET控制台应用的基本结构:输入处理、逻辑处理和输出显示。
第二章:C#基础语法深入解析
2.1 变量与数据类型
C#是一种强类型语言,这意味着每个变量都有明确的类型。让我们从基础数据类型开始:
// 整数类型
int age = 25; // 32位有符号整数
long bigNumber = 123456789L; // 64位有符号整数
short smallNumber = 100; // 16位有符号整数
byte binaryData = 0xFF; // 8位无符号整数
// 浮点类型
float temperature = 23.5f; // 单精度浮点数(注意f后缀)
double pi = 3.1415926535; // 双精度浮点数(默认小数类型)
decimal price = 19.99m; // 高精度小数(用于金融计算,注意m后缀)
// 字符串和字符
string greeting = "Hello C#"; // 字符串
char grade = 'A'; // 单个字符
// 布尔类型
bool isCompleted = true; // true或false
// 特殊类型
object anyType = 123; // 可以存储任何类型
string? nullableString = null; // 可空类型(C# 8.0+)
类型推断:使用var关键字可以让编译器自动推断变量类型:
var message = "这是一个字符串"; // 编译器推断为string
var number = 100; // 推断为int
var numbers = new[] { 1, 2, 3 }; // 推断为int[]
2.2 流程控制语句
条件语句
// if-else 示例
Console.Write("请输入你的年龄:");
int userAge = int.Parse(Console.ReadLine()!);
if (userAge >= 18)
{
Console.WriteLine("你是成年人。");
}
else if (userAge >= 13)
{
Console.WriteLine("你是青少年。");
}
else
{
Console.WriteLine("你是儿童。");
}
// switch 表达式(C# 8.0+)
string dayType = userAge switch
{
>= 18 => "成年人",
>= 13 => "青少年",
_ => "儿童"
};
// switch 语句传统用法
Console.Write("请输入星期几(1-7):");
int dayOfWeek = int.Parse(Console.ReadLine()!);
switch (dayOfWeek)
{
case 1:
Console.WriteLine("星期一");
break;
case 2:
Console.WriteLine("星期二");
break;
case 6:
case 7:
Console.WriteLine("周末");
break;
default:
Console.WriteLine("工作日");
break;
}
循环语句
// for 循环 - 计算1到100的和
int sum = 0;
for (int i = 1; i <= 100; i++)
{
sum += i;
}
Console.WriteLine($"1到100的和是:{sum}");
// foreach 循环 - 遍历数组
int[] numbers = { 10, 20, 30, 40, 50 };
foreach (int num in numbers)
{
Console.WriteLine($"当前数字:{num}");
}
// while 循环 - 用户输入验证
string input;
while (true)
{
Console.Write("请输入一个正整数(输入0退出):");
input = Console.ReadLine()!;
if (input == "0") break;
if (int.TryParse(input, out int result) && result > 0)
{
Console.WriteLine($"你输入了有效的正整数:{result}");
}
else
{
Console.WriteLine("输入无效,请重试。");
}
}
// do-while 循环 - 至少执行一次
string password;
do
{
Console.Write("请输入密码(至少6位):");
password = Console.ReadLine()!;
} while (password.Length < 6);
Console.WriteLine("密码设置成功!");
2.3 方法(函数)的定义与使用
方法是C#中代码重用的基本单元。让我们学习如何定义和调用方法:
// 基本方法定义
public class Calculator
{
// 无参数无返回值的方法
public void SayHello()
{
Console.WriteLine("你好,我是计算器!");
}
// 有参数无返回值的方法
public void PrintSum(int a, int b)
{
int result = a + b;
Console.WriteLine($"{a} + {b} = {result}");
}
// 有参数有返回值的方法
public int Add(int a, int b)
{
return a + b;
}
// 方法重载 - 同名方法,不同参数
public int Multiply(int a, int b)
{
return a * b;
}
public double Multiply(double a, double b)
{
return a * b;
}
// 可选参数和命名参数
public void DisplayInfo(string name, int age = 18, string occupation = "学生")
{
Console.WriteLine($"姓名:{name},年龄:{age},职业:{occupation}");
}
// 参数数组(params)
public int Sum(params int[] numbers)
{
int total = 0;
foreach (int num in numbers)
{
total += num;
}
return total;
}
}
// 使用示例
class Program
{
static void Main()
{
Calculator calc = new Calculator();
calc.SayHello();
calc.PrintSum(5, 3);
int result = calc.Add(10, 20);
Console.WriteLine($"加法结果:{result}");
// 方法重载调用
Console.WriteLine($"整数乘法:{calc.Multiply(4, 5)}");
Console.WriteLine($"浮点乘法:{calc.Multiply(2.5, 4.0)}");
// 命名参数调用
calc.DisplayInfo("张三"); // 使用默认参数
calc.DisplayInfo("李四", 25); // 只覆盖第一个默认参数
calc.DisplayInfo("王五", occupation: "工程师"); // 命名参数
// 参数数组
Console.WriteLine($"1+2+3+4+5 = {calc.Sum(1, 2, 3, 4, 5)}");
}
}
第三章:面向对象编程(OOP)核心概念
3.1 类与对象
面向对象编程是.NET的核心范式。让我们通过一个实际的例子来理解类和对象:
// 定义一个汽车类
public class Car
{
// 字段(私有成员)
private string make;
private string model;
private int year;
private double speed;
private bool isEngineRunning;
// 构造函数
public Car(string make, string model, int year)
{
this.make = make;
this.model = model;
this.year = year;
this.speed = 0;
this.isEngineRunning = false;
}
// 属性(封装字段)
public string Make
{
get { return make; }
set { make = value; }
}
public string Model
{
get { return model; }
set { model = value; }
}
public int Year
{
get { return year; }
set { year = value; }
}
// 只读属性
public string Description => $"{year} {make} {model}";
// 方法
public void StartEngine()
{
if (!isEngineRunning)
{
isEngineRunning = true;
Console.WriteLine($"{Description} 的引擎启动了!");
}
else
{
Console.WriteLine("引擎已经在运行中。");
}
}
public void StopEngine()
{
if (isEngineRunning)
{
isEngineRunning = false;
speed = 0;
Console.WriteLine($"{Description} 的引擎停止了。");
}
}
public void Accelerate(double increment)
{
if (isEngineRunning)
{
speed += increment;
Console.WriteLine($"{Description} 当前速度:{speed} km/h");
}
else
{
Console.WriteLine("请先启动引擎!");
}
}
public void Brake(double decrement)
{
speed = Math.Max(0, speed - decrement);
Console.WriteLine($"{Description} 减速后速度:{speed} km/h");
}
// 静态成员
public static int TotalCars { get; private set; } = 0;
public static void DisplayTotalCars()
{
Console.WriteLine($"总共创建了 {TotalCars} 辆汽车");
}
// 析构函数(用于清理资源)
~Car()
{
Console.WriteLine($"{Description} 被销毁了");
}
}
// 使用示例
class Program
{
static void Main()
{
// 创建对象(实例化)
Car myCar = new Car("Toyota", "Camry", 2023);
Car yourCar = new Car("Honda", "Civic", 2022);
// 访问属性和方法
Console.WriteLine(myCar.Description);
myCar.StartEngine();
myCar.Accelerate(30);
myCar.Accelerate(20);
myCar.Brake(15);
// 静态成员访问
Car.DisplayTotalCars();
// 对象销毁
myCar = null; // 触发垃圾回收
yourCar = null;
// 强制垃圾回收(仅用于演示,实际开发中不推荐)
GC.Collect();
}
}
3.2 继承与多态
继承允许我们创建新类基于现有类,而多态允许我们以统一的方式处理不同类型的对象。
// 基类:动物
public abstract class Animal
{
public string Name { get; set; }
public int Age { get; set; }
// 抽象方法(必须在派生类中实现)
public abstract void MakeSound();
// 虚方法(可以在派生类中重写)
public virtual void DisplayInfo()
{
Console.WriteLine($"我叫{Name},今年{Age}岁");
}
// 密封方法(不能被重写)
public sealed void Sleep()
{
Console.WriteLine($"{Name}正在睡觉...");
}
}
// 派生类:狗
public class Dog : Animal
{
public string Breed { get; set; }
// 重写抽象方法
public override void MakeSound()
{
Console.WriteLine($"{Name}说:汪汪汪!");
}
// 重写虚方法
public override void DisplayInfo()
{
base.DisplayInfo(); // 调用基类方法
Console.WriteLine($"品种:{Breed}");
}
// 派生类特有方法
public void Fetch()
{
Console.WriteLine($"{Name}正在捡球...");
}
}
// 派生类:猫
public class Cat : Animal
{
public bool IsLazy { get; set; }
public override void MakeSound()
{
Console.WriteLine($"{Name}说:喵喵喵!");
}
public override void DisplayInfo()
{
base.DisplayInfo();
Console.WriteLine($"懒惰状态:{(IsLazy ? "是" : "否")}");
}
public void Scratch()
{
Console.WriteLine($"{Name}正在抓沙发...");
}
}
// 多态演示
class Program
{
static void Main()
{
// 多态数组
Animal[] animals = new Animal[]
{
new Dog { Name = "旺财", Age = 3, Breed = "金毛" },
new Cat { Name = "咪咪", Age = 2, IsLazy = true },
new Dog { Name = "大黄", Age = 5, Breed = "哈士奇" }
};
// 统一处理不同类型的对象
foreach (Animal animal in animals)
{
animal.DisplayInfo();
animal.MakeSound();
// 类型检查和转换
if (animal is Dog dog)
{
dog.Fetch();
}
else if (animal is Cat cat)
{
cat.Scratch();
}
Console.WriteLine("---");
}
// 抽象类不能直接实例化
// Animal animal = new Animal(); // 编译错误
// 但可以作为引用类型
Animal myPet = new Dog { Name = "乐乐", Age = 1, Breed = "柯基" };
myPet.MakeSound();
}
}
3.3 接口与抽象类
接口定义契约,抽象类提供部分实现。让我们通过一个实际的例子来理解它们的区别:
// 接口:定义飞行能力
public interface IFlyable
{
void Fly();
double MaxAltitude { get; }
}
// 接口:定义游泳能力
public interface ISwimmable
{
void Swim();
double MaxDepth { get; }
}
// 抽象类:提供基础实现
public abstract class Vehicle
{
public string Brand { get; set; }
public int Year { get; set; }
// 抽象方法
public abstract void Start();
// 虚方法(提供默认实现)
public virtual void Stop()
{
Console.WriteLine($"{Brand} 车辆停止");
}
// 具体方法
public void DisplayBrand()
{
Console.WriteLine($"品牌:{Brand}, 年份:{Year}");
}
}
// 具体类:实现接口和继承抽象类
public class FlyingCar : Vehicle, IFlyable, ISwimmable
{
public double MaxAltitude { get; set; } = 5000;
public double MaxDepth { get; set; } = 100;
// 实现抽象方法
public override void Start()
{
Console.WriteLine("启动陆地、空中和水中模式");
}
// 实现接口方法
public void Fly()
{
Console.WriteLine($"飞行高度可达 {MaxAltitude} 米");
}
public void Swim()
{
Console.WriteLine($"潜水深度可达 {MaxDepth} 米");
}
// 可选:重写虚方法
public override void Stop()
{
base.Stop();
Console.WriteLine("所有模式已关闭");
}
}
// 另一个实现接口的类
public class Airplane : Vehicle, IFlyable
{
public double MaxAltitude { get; set; } = 12000;
public override void Start()
{
Console.WriteLine("启动引擎,准备起飞");
}
public void Fly()
{
Console.WriteLine($"飞机在 {MaxAltitude} 米高空飞行");
}
}
class Program
{
static void Main()
{
// 使用接口引用
IFlyable flyingObject = new FlyingCar
{
Brand = "Tesla",
Year = 2024,
MaxAltitude = 8000
};
flyingObject.Fly();
// 使用抽象类引用
Vehicle vehicle = new Airplane
{
Brand = "Boeing",
Year = 2023
};
vehicle.Start();
vehicle.DisplayBrand();
// 检查接口实现
if (vehicle is IFlyable flyable)
{
flyable.Fly();
}
// 多接口实现
FlyingCar superCar = new FlyingCar
{
Brand = "Audi",
Year = 2024
};
// 分别调用不同接口的方法
IFlyable fly = superCar;
ISwimmable swim = superCar;
fly.Fly();
swim.Swim();
}
}
第四章:.NET核心特性与高级语法
4.1 委托与事件
委托是C#中实现回调机制和事件处理的核心,理解委托对于掌握.NET编程至关重要。
// 定义委托类型
public delegate void NotificationHandler(string message);
// 事件发布者
public class ProcessManager
{
// 声明事件
public event NotificationHandler? OnProcessStart;
public event NotificationHandler? OnProcessComplete;
public void StartProcess()
{
// 触发开始事件
OnProcessStart?.Invoke("进程开始执行");
// 模拟工作
Console.WriteLine("正在处理数据...");
Thread.Sleep(2000);
// 触发完成事件
OnProcessComplete?.Invoke("进程执行完成");
}
}
// 事件订阅者
public class Logger
{
public void LogStart(string message)
{
Console.WriteLine($"[开始] {DateTime.Now}: {message}");
}
public void LogComplete(string message)
{
Console.WriteLine($"[完成] {DateTime.Now}: {message}");
}
}
public class Notifier
{
public void SendNotification(string message)
{
Console.WriteLine($"发送通知:{message}");
}
}
class Program
{
static void Main()
{
ProcessManager manager = new ProcessManager();
Logger logger = new Logger();
Notifier notifier = new Notifier();
// 订阅事件(多播委托)
manager.OnProcessStart += logger.LogStart;
manager.OnProcessStart += notifier.SendNotification;
manager.OnProcessComplete += logger.LogComplete;
// 执行过程
manager.StartProcess();
// 取消订阅
manager.OnProcessStart -= notifier.SendNotification;
Console.WriteLine("\n再次执行(减少订阅者):");
manager.StartProcess();
}
}
4.2 泛型编程
泛型提供了类型安全和代码重用,是现代C#编程的重要特性。
// 泛型类
public class Repository<T> where T : class, new()
{
private List<T> items = new List<T>();
// 添加项目
public void Add(T item)
{
items.Add(item);
Console.WriteLine($"添加了 {typeof(T).Name} 类型的项目");
}
// 获取所有项目
public IEnumerable<T> GetAll()
{
return items;
}
// 查找项目
public T? Find(Predicate<T> predicate)
{
return items.Find(predicate);
}
// 删除项目
public bool Remove(T item)
{
return items.Remove(item);
}
// 泛型方法
public T2 Convert<T2>(Func<T, T2> converter)
{
if (items.Count == 0) throw new InvalidOperationException("没有数据");
return converter(items[0]);
}
}
// 泛型约束示例
public class DataProcessor<T> where T : IComparable<T>
{
public T GetMax(T a, T b)
{
return a.CompareTo(b) > 0 ? a : b;
}
public T GetMin(T a, T b)
{
return a.CompareTo(b) < 0 ? a : b;
}
}
// 使用示例
public class Product
{
public string Name { get; set; } = "";
public decimal Price { get; set; }
public override string ToString() => $"{Name}: ${Price}";
}
class Program
{
static void Main()
{
// 使用泛型仓储
var productRepo = new Repository<Product>();
productRepo.Add(new Product { Name = "笔记本电脑", Price = 999.99m });
productRepo.Add(new Product { Name = "鼠标", Price = 29.99m });
productRepo.Add(new Product { Name = "键盘", Price = 79.99m });
// 查找产品
var expensiveProduct = productRepo.Find(p => p.Price > 500);
Console.WriteLine($"最贵的产品:{expensiveProduct}");
// 泛型方法
var firstProduct = productRepo.GetAll().First();
string productName = productRepo.Convert(p => p.Name);
Console.WriteLine($"转换结果:{productName}");
// 使用约束的泛型类
var intProcessor = new DataProcessor<int>();
Console.WriteLine($"最大值:{intProcessor.GetMax(10, 20)}");
var stringProcessor = new DataProcessor<string>();
Console.WriteLine($"最长字符串:{stringProcessor.GetMax("Hello", "World")}");
}
}
4.3 LINQ(语言集成查询)
LINQ是.NET的杀手级特性,让我们能够以统一的方式查询各种数据源。
using System.Linq;
// 数据模型
public class Student
{
public int Id { get; set; }
public string Name { get; set; } = "";
public int Age { get; set; }
public string Grade { get; set; } = "";
public List<int> Scores { get; set; } = new List<int>();
}
class Program
{
static void Main()
{
// 创建测试数据
var students = new List<Student>
{
new Student { Id = 1, Name = "张三", Age = 20, Grade = "A", Scores = new List<int> { 85, 90, 88 } },
new Student { Id = 2, Name = "李四", Age = 22, Grade = "B", Scores = new List<int> { 75, 80, 78 } },
new Student { Id = 3, Name = "王五", Age = 21, Grade = "A", Scores = new List<int> { 95, 92, 94 } },
new Student { Id = 4, Name = "赵六", Age = 23, Grade = "C", Scores = new List<int> { 65, 70, 68 } },
new Student { Id = 5, Name = "钱七", Age = 20, Grade = "B", Scores = new List<int> { 82, 85, 83 } }
};
// 1. 基础查询 - 使用查询语法
var olderStudents = from s in students
where s.Age > 20
select s.Name;
Console.WriteLine("20岁以上的学生:" + string.Join(", ", olderStudents));
// 2. 方法语法
var aGradeStudents = students
.Where(s => s.Grade == "A")
.Select(s => s.Name);
Console.WriteLine("A等级学生:" + string.Join(", ", aGradeStudents));
// 3. 排序
var sortedStudents = students
.OrderByDescending(s => s.Age)
.ThenBy(s => s.Name);
Console.WriteLine("\n按年龄降序排列:");
foreach (var s in sortedStudents)
{
Console.WriteLine($"{s.Name} - {s.Age}岁");
}
// 4. 聚合操作
var averageAge = students.Average(s => s.Age);
var maxAge = students.Max(s => s.Age);
var minAge = students.Min(s => s.Age);
Console.WriteLine($"\n平均年龄:{averageAge:F1}");
Console.WriteLine($"最大年龄:{maxAge}");
Console.WriteLine($"最小年龄:{minAge}");
// 5. 分组
var groupedByGrade = students.GroupBy(s => s.Grade);
Console.WriteLine("\n按等级分组:");
foreach (var group in groupedByGrade)
{
Console.WriteLine($"等级 {group.Key}: {string.Join(", ", group.Select(s => s.Name))}");
}
// 6. 多个集合操作
var highPerformers = students
.Where(s => s.Scores.Average() > 85)
.Select(s => new
{
s.Name,
AverageScore = s.Scores.Average(),
TotalScore = s.Scores.Sum()
});
Console.WriteLine("\n成绩优秀的学生:");
foreach (var p in highPerformers)
{
Console.WriteLine($"{p.Name} - 平均分:{p.AverageScore:F1}, 总分:{p.TotalScore}");
}
// 7. 连接操作(模拟另一个集合)
var studentAges = students.Select(s => new { s.Id, s.Age });
var studentNames = students.Select(s => new { s.Id, s.Name });
var joined = from age in studentAges
join name in studentNames on age.Id equals name.Id
select new { name.Name, age.Age };
Console.WriteLine("\n连接查询结果:");
foreach (var item in joined)
{
Console.WriteLine($"{item.Name} - {item.Age}");
}
// 8. 分页
int pageSize = 2;
int pageNumber = 1;
var pagedStudents = students
.Skip((pageNumber - 1) * pageSize)
.Take(pageSize);
Console.WriteLine($"\n第 {pageNumber} 页(每页 {pageSize} 条):");
foreach (var s in pagedStudents)
{
Console.WriteLine(s.Name);
}
// 9. 检查条件
bool anyFailed = students.Any(s => s.Grade == "C");
bool allPassed = students.All(s => s.Grade != "C");
Console.WriteLine($"\n是否有C等级:{anyFailed}");
Console.WriteLine($"是否全部通过:{allPassed}");
}
}
第五章:异常处理与调试技巧
5.1 异常处理最佳实践
// 自定义异常类
public class InsufficientFundsException : Exception
{
public decimal Balance { get; }
public decimal Required { get; }
public InsufficientFundsException(decimal balance, decimal required)
: base($"余额不足!当前余额:{balance},需要:{required}")
{
Balance = balance;
Required = required;
}
}
public class BankAccount
{
public string AccountNumber { get; }
public decimal Balance { get; private set; }
public BankAccount(string accountNumber, decimal initialBalance)
{
AccountNumber = accountNumber;
Balance = initialBalance;
}
// 多个catch块和finally
public void Withdraw(decimal amount)
{
try
{
if (amount <= 0)
{
throw new ArgumentException("取款金额必须为正数", nameof(amount));
}
if (amount > Balance)
{
throw new InsufficientFundsException(Balance, amount);
}
Balance -= amount;
Console.WriteLine($"成功取款:{amount},剩余余额:{Balance}");
}
catch (InsufficientFundsException ex)
{
Console.WriteLine($"余额不足错误:{ex.Message}");
Console.WriteLine($"当前余额:{ex.Balance},需要:{ex.Required}");
}
catch (ArgumentException ex)
{
Console.WriteLine($"参数错误:{ex.Message}");
}
catch (Exception ex)
{
Console.WriteLine($"未知错误:{ex.Message}");
// 记录日志
LogError(ex);
}
finally
{
Console.WriteLine("取款操作完成");
}
}
// 使用try-pattern
public bool TryWithdraw(decimal amount, out decimal actualAmount)
{
actualAmount = 0;
try
{
Withdraw(amount);
actualAmount = amount;
return true;
}
catch
{
return false;
}
}
private void LogError(Exception ex)
{
// 实际项目中这里会写入日志文件或数据库
Console.WriteLine($"[ERROR] {DateTime.Now}: {ex.GetType().Name} - {ex.Message}");
}
}
// 异常过滤器(C# 6.0+)
public class ExceptionFilterDemo
{
public void ProcessWithFilter(int value)
{
try
{
if (value < 0) throw new ArgumentOutOfRangeException(nameof(value));
if (value == 0) throw new DivideByZeroException();
if (value == 1) throw new InvalidOperationException("特定错误");
Console.WriteLine($"处理值:{value}");
}
catch (Exception ex) when (ex is ArgumentOutOfRangeException)
{
Console.WriteLine("参数超出范围");
}
catch (Exception ex) when (ex.Message.Contains("特定错误"))
{
Console.WriteLine("捕获到特定的 InvalidOperationException");
}
catch (Exception ex)
{
Console.WriteLine($"其他错误:{ex.Message}");
}
}
}
class Program
{
static void Main()
{
var account = new BankAccount("123456", 1000);
// 正常取款
account.Withdraw(300);
// 余额不足
account.Withdraw(800);
// 无效参数
account.Withdraw(-50);
// 使用Try模式
decimal amount;
if (account.TryWithdraw(200, out amount))
{
Console.WriteLine($"TryWithdraw成功,取款:{amount}");
}
// 异常过滤器演示
var filterDemo = new ExceptionFilterDemo();
filterDemo.ProcessWithFilter(-1);
filterDemo.ProcessWithFilter(0);
filterDemo.ProcessWithFilter(1);
filterDemo.ProcessWithFilter(5);
}
}
5.2 调试技巧
在Visual Studio中,有效的调试技巧可以大大提高开发效率:
断点设置:
- 条件断点:右键断点 → 条件 → 输入表达式(如
x > 100) - 断点操作:可以记录日志而不中断执行
- 函数断点:在函数入口处设置断点
- 条件断点:右键断点 → 条件 → 输入表达式(如
监视窗口:
- 添加监视表达式
- 实时查看变量变化
- 查看对象的所有属性
即时窗口:
- 执行代码片段
- 修改变量值
- 调用方法
调用堆栈:
- 查看方法调用链
- 快速导航到上层调用
内存分析:
- 使用内存分析器查找内存泄漏
- 分析对象分配情况
第六章:数据访问与数据库操作
6.1 ADO.NET基础
ADO.NET是.NET平台上传统的数据库访问技术,虽然现在推荐使用Entity Framework Core,但理解ADO.NET仍然很重要。
using System.Data;
using System.Data.SqlClient;
public class AdoNetDemo
{
private readonly string connectionString = "Server=localhost;Database=MyDB;Trusted_Connection=True;";
// 创建数据库和表(仅用于演示)
public void SetupDatabase()
{
try
{
// 连接到master数据库创建新数据库
var masterConnStr = "Server=localhost;Trusted_Connection=True;";
using (var conn = new SqlConnection(masterConnStr))
{
conn.Open();
// 创建数据库
var createDbCmd = new SqlCommand(
"IF NOT EXISTS (SELECT name FROM sys.databases WHERE name = 'MyDB') " +
"CREATE DATABASE MyDB", conn);
createDbCmd.ExecuteNonQuery();
// 切换到MyDB并创建表
using (var cmd = new SqlCommand("USE MyDB", conn))
{
cmd.ExecuteNonQuery();
}
// 创建用户表
var createTableCmd = new SqlCommand(@"
IF NOT EXISTS (SELECT * FROM sysobjects WHERE name='Users' AND xtype='U')
CREATE TABLE Users (
Id INT PRIMARY KEY IDENTITY(1,1),
Name NVARCHAR(100) NOT NULL,
Email NVARCHAR(100),
Age INT,
CreatedDate DATETIME2 DEFAULT GETDATE()
)", conn);
createTableCmd.ExecuteNonQuery();
}
}
catch (Exception ex)
{
Console.WriteLine($"数据库设置错误:{ex.Message}");
}
}
// 插入数据
public void InsertUser(string name, string email, int age)
{
using (var conn = new SqlConnection(connectionString))
{
conn.Open();
// 使用参数化查询防止SQL注入
var cmd = new SqlCommand(
"INSERT INTO Users (Name, Email, Age) VALUES (@Name, @Email, @Age)",
conn);
cmd.Parameters.AddWithValue("@Name", name);
cmd.Parameters.AddWithValue("@Email", email);
cmd.Parameters.AddWithValue("@Age", age);
int rowsAffected = cmd.ExecuteNonQuery();
Console.WriteLine($"插入了 {rowsAffected} 行数据");
}
}
// 查询数据
public void GetAllUsers()
{
using (var conn = new SqlConnection(connectionString))
{
conn.Open();
var cmd = new SqlCommand("SELECT Id, Name, Email, Age, CreatedDate FROM Users", conn);
using (var reader = cmd.ExecuteReader())
{
Console.WriteLine("\n所有用户:");
while (reader.Read())
{
Console.WriteLine($"ID: {reader["Id"]}, " +
$"姓名: {reader["Name"]}, " +
$"邮箱: {reader["Email"]}, " +
$"年龄: {reader["Age"]}, " +
$"创建时间: {reader["CreatedDate"]}");
}
}
}
}
// 使用事务
public void TransferMoney(int fromUserId, int toUserId, decimal amount)
{
using (var conn = new SqlConnection(connectionString))
{
conn.Open();
var transaction = conn.BeginTransaction();
try
{
// 扣款
var withdrawCmd = new SqlCommand(
"UPDATE Users SET Balance = Balance - @Amount WHERE Id = @Id",
conn, transaction);
withdrawCmd.Parameters.AddWithValue("@Amount", amount);
withdrawCmd.Parameters.AddWithValue("@Id", fromUserId);
withdrawCmd.ExecuteNonQuery();
// 存款
var depositCmd = new SqlCommand(
"UPDATE Users SET Balance = Balance + @Amount WHERE Id = @Id",
conn, transaction);
depositCmd.Parameters.AddWithValue("@Amount", amount);
depositCmd.Parameters.AddWithValue("@Id", toUserId);
depositCmd.ExecuteNonQuery();
// 提交事务
transaction.Commit();
Console.WriteLine("转账成功");
}
catch (Exception)
{
// 回滚事务
transaction.Rollback();
Console.WriteLine("转账失败,已回滚");
throw;
}
}
}
}
6.2 Entity Framework Core
EF Core是现代.NET应用推荐的数据访问技术,它提供了对象关系映射(ORM)功能。
using Microsoft.EntityFrameworkCore;
// 1. 定义模型
public class Blog
{
public int BlogId { get; set; }
public string Url { get; set; } = "";
public DateTime CreatedDate { get; set; }
// 导航属性
public List<Post> Posts { get; set; } = new List<Post>();
}
public class Post
{
public int PostId { get; set; }
public string Title { get; set; } = "";
public string Content { get; set; } = "";
public DateTime PublishedDate { get; set; }
// 外键
public int BlogId { get; set; }
public Blog Blog { get; set; } = null!;
}
// 2. 定义DbContext
public class BloggingContext : DbContext
{
public DbSet<Blog> Blogs { get; set; } = null!;
public DbSet<Post> Posts { get; set; } = null!;
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer(
"Server=localhost;Database=BloggingDB;Trusted_Connection=True;TrustServerCertificate=True");
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
// 配置关系
modelBuilder.Entity<Blog>()
.HasMany(b => b.Posts)
.WithOne(p => p.Blog)
.HasForeignKey(p => p.BlogId);
// 配置索引
modelBuilder.Entity<Blog>()
.HasIndex(b => b.Url)
.IsUnique();
}
}
// 3. 使用EF Core
public class EfCoreDemo
{
public void Run()
{
// 确保数据库存在
using (var context = new BloggingContext())
{
context.Database.EnsureCreated();
}
// 创建数据
CreateBlogs();
// 查询数据
QueryBlogs();
// 更新数据
UpdateBlog();
// 删除数据
DeleteBlog();
}
private void CreateBlogs()
{
using (var context = new BloggingContext())
{
var blog = new Blog
{
Url = "https://example.com",
CreatedDate = DateTime.Now,
Posts = new List<Post>
{
new Post { Title = "EF Core入门", Content = "这是第一篇文章", PublishedDate = DateTime.Now },
new Post { Title = "EF Core进阶", Content = "这是第二篇文章", PublishedDate = DateTime.Now.AddDays(-1) }
}
};
context.Blogs.Add(blog);
int changes = context.SaveChanges();
Console.WriteLine($"创建了 {changes} 个实体");
}
}
private void QueryBlogs()
{
using (var context = new BloggingContext())
{
// 延迟加载
var blogs = context.Blogs
.Include(b => b.Posts) // 包含相关数据
.Where(b => b.CreatedDate > DateTime.Now.AddDays(-7))
.OrderByDescending(b => b.CreatedDate)
.ToList();
foreach (var blog in blogs)
{
Console.WriteLine($"\n博客:{blog.Url} (创建于 {blog.CreatedDate})");
foreach (var post in blog.Posts)
{
Console.WriteLine($" - {post.Title}: {post.Content}");
}
}
}
}
private void UpdateBlog()
{
using (var context = new BloggingContext())
{
var blog = context.Blogs.First();
blog.Url = "https://updated-example.com";
int changes = context.SaveChanges();
Console.WriteLine($"更新了 {changes} 个实体");
}
}
private void DeleteBlog()
{
using (var context = new BloggingContext())
{
var blog = context.Blogs.First();
context.Blogs.Remove(blog);
int changes = context.SaveChanges();
Console.WriteLine($"删除了 {changes} 个实体");
}
}
}
第七章:ASP.NET Core Web开发
7.1 创建Web API
ASP.NET Core是构建现代Web应用和API的首选框架。
// Program.cs (ASP.NET Core 6+ 的最小主机模型)
using Microsoft.EntityFrameworkCore;
var builder = WebApplication.CreateBuilder(args);
// 添加服务到容器
builder.Services.AddControllers();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
// 添加数据库上下文
builder.Services.AddDbContext<TodoContext>(options =>
options.UseSqlServer(builder.Configuration.GetConnectionString("DefaultConnection")));
// 添加内存数据库(用于开发)
// builder.Services.AddDbContext<TodoContext>(options =>
// options.UseInMemoryDatabase("TodoDb"));
var app = builder.Build();
// 配置HTTP请求管道
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
app.Run();
// Models/TodoItem.cs
public class TodoItem
{
public int Id { get; set; }
public string? Title { get; set; }
public bool IsComplete { get; set; }
}
// Data/TodoContext.cs
public class TodoContext : DbContext
{
public TodoContext(DbContextOptions<TodoContext> options) : base(options) { }
public DbSet<TodoItem> TodoItems { get; set; } = null!;
}
// Controllers/TodoController.cs
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
[ApiController]
[Route("api/[controller]")]
public class TodoController : ControllerBase
{
private readonly TodoContext _context;
public TodoController(TodoContext context)
{
_context = context;
}
// GET: api/todo
[HttpGet]
public async Task<ActionResult<IEnumerable<TodoItem>>> GetTodoItems()
{
return await _context.TodoItems.ToListAsync();
}
// GET: api/todo/5
[HttpGet("{id}")]
public async Task<ActionResult<TodoItem>> GetTodoItem(int id)
{
var todoItem = await _context.TodoItems.FindAsync(id);
if (todoItem == null)
{
return NotFound();
}
return todoItem;
}
// POST: api/todo
[HttpPost]
public async Task<ActionResult<TodoItem>> PostTodoItem(TodoItem todoItem)
{
_context.TodoItems.Add(todoItem);
await _context.SaveChangesAsync();
return CreatedAtAction(nameof(GetTodoItem), new { id = todoItem.Id }, todoItem);
}
// PUT: api/todo/5
[HttpPut("{id}")]
public async Task<IActionResult> PutTodoItem(int id, TodoItem todoItem)
{
if (id != todoItem.Id)
{
return BadRequest();
}
_context.Entry(todoItem).State = EntityState.Modified;
try
{
await _context.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
if (!TodoItemExists(id))
{
return NotFound();
}
else
{
throw;
}
}
return NoContent();
}
// DELETE: api/todo/5
[HttpDelete("{id}")]
public async Task<IActionResult> DeleteTodoItem(int id)
{
var todoItem = await _context.TodoItems.FindAsync(id);
if (todoItem == null)
{
return NotFound();
}
_context.TodoItems.Remove(todoItem);
await _context.SaveChangesAsync();
return NoContent();
}
private bool TodoItemExists(int id)
{
return _context.TodoItems.Any(e => e.Id == id);
}
}
7.2 中间件与依赖注入
// 自定义中间件
public class RequestTimingMiddleware
{
private readonly RequestDelegate _next;
private readonly ILogger<RequestTimingMiddleware> _logger;
public RequestTimingMiddleware(RequestDelegate next, ILogger<RequestTimingMiddleware> logger)
{
_next = next;
_logger = logger;
}
public async Task InvokeAsync(HttpContext context)
{
var stopwatch = System.Diagnostics.Stopwatch.StartNew();
await _next(context);
stopwatch.Stop();
var elapsed = stopwatch.ElapsedMilliseconds;
_logger.LogInformation(
"请求 {Method} {Path} 耗时 {Elapsed}ms",
context.Request.Method,
context.Request.Path,
elapsed);
}
}
// 依赖注入示例
public interface IEmailService
{
Task SendAsync(string to, string subject, string body);
}
public class EmailService : IEmailService
{
public async Task SendAsync(string to, string subject, string body)
{
// 模拟发送邮件
await Task.Delay(100);
Console.WriteLine($"发送邮件到 {to}: {subject}");
}
}
public interface INotificationService
{
Task NotifyAsync(string message);
}
public class NotificationService : INotificationService
{
private readonly IEmailService _emailService;
// 构造函数注入
public NotificationService(IEmailService emailService)
{
_emailService = emailService;
}
public async Task NotifyAsync(string message)
{
await _emailService.SendAsync("admin@example.com", "通知", message);
}
}
// 在Program.cs中配置服务
// builder.Services.AddScoped<IEmailService, EmailService>();
// builder.Services.AddScoped<INotificationService, NotificationService>();
第八章:实战项目 - 构建任务管理系统
8.1 项目架构设计
让我们通过一个完整的任务管理系统来整合所学知识。
// 项目结构:
// TaskManager/
// ├── Models/
// │ ├── TaskItem.cs
// │ ├── User.cs
// │ └── Project.cs
// ├── Services/
// │ ├── ITaskService.cs
// │ ├── TaskService.cs
// │ └── IProjectService.cs
// ├── Data/
// │ └── TaskContext.cs
// ├── Controllers/
// │ └── TasksController.cs
// └── Program.cs
// Models/TaskItem.cs
public class TaskItem
{
public int Id { get; set; }
public string Title { get; set; } = "";
public string? Description { get; set; }
public TaskStatus Status { get; set; } = TaskStatus.Pending;
public PriorityLevel Priority { get; set; } = PriorityLevel.Medium;
public DateTime DueDate { get; set; }
public DateTime CreatedDate { get; set; } = DateTime.Now;
// 外键关系
public int ProjectId { get; set; }
public Project Project { get; set; } = null!;
public int? AssignedToUserId { get; set; }
public User? AssignedTo { get; set; }
}
public enum TaskStatus
{
Pending,
InProgress,
Completed,
OnHold,
Cancelled
}
public enum PriorityLevel
{
Low,
Medium,
High,
Critical
}
// Models/User.cs
public class User
{
public int Id { get; set; }
public string Username { get; set; } = "";
public string Email { get; set; } = "";
public List<TaskItem> AssignedTasks { get; set; } = new List<TaskItem>();
}
// Models/Project.cs
public class Project
{
public int Id { get; set; }
public string Name { get; set; } = "";
public string? Description { get; set; }
public DateTime StartDate { get; set; }
public DateTime? EndDate { get; set; }
public List<TaskItem> Tasks { get; set; } = new List<TaskItem>();
}
// Services/ITaskService.cs
public interface ITaskService
{
Task<IEnumerable<TaskItem>> GetAllTasksAsync();
Task<TaskItem?> GetTaskByIdAsync(int id);
Task<TaskItem> CreateTaskAsync(TaskItem task);
Task<bool> UpdateTaskAsync(int id, TaskItem task);
Task<bool> DeleteTaskAsync(int id);
Task<IEnumerable<TaskItem>> GetTasksByStatusAsync(TaskStatus status);
Task<IEnumerable<TaskItem>> GetTasksByUserAsync(int userId);
}
// Services/TaskService.cs
public class TaskService : ITaskService
{
private readonly TaskContext _context;
public TaskService(TaskContext context)
{
_context = context;
}
public async Task<IEnumerable<TaskItem>> GetAllTasksAsync()
{
return await _context.Tasks
.Include(t => t.Project)
.Include(t => t.AssignedTo)
.OrderByDescending(t => t.CreatedDate)
.ToListAsync();
}
public async Task<TaskItem?> GetTaskByIdAsync(int id)
{
return await _context.Tasks
.Include(t => t.Project)
.Include(t => t.AssignedTo)
.FirstOrDefaultAsync(t => t.Id == id);
}
public async Task<TaskItem> CreateTaskAsync(TaskItem task)
{
_context.Tasks.Add(task);
await _context.SaveChangesAsync();
return task;
}
public async Task<bool> UpdateTaskAsync(int id, TaskItem task)
{
if (id != task.Id) return false;
_context.Entry(task).State = EntityState.Modified;
try
{
await _context.SaveChangesAsync();
return true;
}
catch (DbUpdateConcurrencyException)
{
return false;
}
}
public async Task<bool> DeleteTaskAsync(int id)
{
var task = await _context.Tasks.FindAsync(id);
if (task == null) return false;
_context.Tasks.Remove(task);
await _context.SaveChangesAsync();
return true;
}
public async Task<IEnumerable<TaskItem>> GetTasksByStatusAsync(TaskStatus status)
{
return await _context.Tasks
.Where(t => t.Status == status)
.Include(t => t.Project)
.ToListAsync();
}
public async Task<IEnumerable<TaskItem>> GetTasksByUserAsync(int userId)
{
return await _context.Tasks
.Where(t => t.AssignedToUserId == userId)
.Include(t => t.Project)
.ToListAsync();
}
}
// Data/TaskContext.cs
public class TaskContext : DbContext
{
public TaskContext(DbContextOptions<TaskContext> options) : base(options) { }
public DbSet<TaskItem> Tasks { get; set; } = null!;
public DbSet<User> Users { get; set; } = null!;
public DbSet<Project> Projects { get; set; } = null!;
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
// 配置关系
modelBuilder.Entity<TaskItem>()
.HasOne(t => t.Project)
.WithMany(p => p.Tasks)
.HasForeignKey(t => t.ProjectId);
modelBuilder.Entity<TaskItem>()
.HasOne(t => t.AssignedTo)
.WithMany(u => u.AssignedTasks)
.HasForeignKey(t => t.AssignedToUserId);
// 配置索引
modelBuilder.Entity<TaskItem>()
.HasIndex(t => t.Status);
modelBuilder.Entity<User>()
.HasIndex(u => u.Email)
.IsUnique();
}
}
// Controllers/TasksController.cs
[ApiController]
[Route("api/[controller]")]
public class TasksController : ControllerBase
{
private readonly ITaskService _taskService;
private readonly INotificationService _notificationService;
public TasksController(ITaskService taskService, INotificationService notificationService)
{
_taskService = taskService;
_notificationService = notificationService;
}
[HttpGet]
public async Task<ActionResult<IEnumerable<TaskItem>>> GetAll()
{
var tasks = await _taskService.GetAllTasksAsync();
return Ok(tasks);
}
[HttpGet("{id}")]
public async Task<ActionResult<TaskItem>> GetById(int id)
{
var task = await _taskService.GetTaskByIdAsync(id);
if (task == null) return NotFound();
return Ok(task);
}
[HttpPost]
public async Task<ActionResult<TaskItem>> Create(TaskItem task)
{
var created = await _taskService.CreateTaskAsync(task);
// 发送通知
if (created.AssignedToUserId.HasValue)
{
await _notificationService.NotifyAsync($"新任务已分配: {created.Title}");
}
return CreatedAtAction(nameof(GetById), new { id = created.Id }, created);
}
[HttpPut("{id}")]
public async Task<IActionResult> Update(int id, TaskItem task)
{
var success = await _taskService.UpdateTaskAsync(id, task);
if (!success) return BadRequest();
return NoContent();
}
[HttpDelete("{id}")]
public async Task<IActionResult> Delete(int id)
{
var success = await _taskService.DeleteTaskAsync(id);
if (!success) return NotFound();
return NoContent();
}
[HttpGet("status/{status}")]
public async Task<ActionResult<IEnumerable<TaskItem>>> GetByStatus(TaskStatus status)
{
var tasks = await _taskService.GetTasksByStatusAsync(status);
return Ok(tasks);
}
[HttpGet("user/{userId}")]
public async Task<ActionResult<IEnumerable<TaskItem>>> GetByUser(int userId)
{
var tasks = await _taskService.GetTasksByUserAsync(userId);
return Ok(tasks);
}
}
8.2 项目配置与运行
// Program.cs
using Microsoft.EntityFrameworkCore;
var builder = WebApplication.CreateBuilder(args);
// 配置服务
builder.Services.AddControllers();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
// 配置数据库(使用内存数据库用于开发)
builder.Services.AddDbContext<TaskContext>(options =>
options.UseInMemoryDatabase("TaskManagerDb"));
// 注册服务
builder.Services.AddScoped<ITaskService, TaskService>();
builder.Services.AddScoped<IEmailService, EmailService>();
builder.Services.AddScoped<INotificationService, NotificationService>();
// 添加自定义中间件
builder.Services.AddScoped<RequestTimingMiddleware>();
var app = builder.Build();
// 配置管道
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseHttpsRedirection();
app.UseAuthorization();
// 使用自定义中间件
app.UseMiddleware<RequestTimingMiddleware>();
app.MapControllers();
// 种子数据(可选)
using (var scope = app.Services.CreateScope())
{
var context = scope.ServiceProvider.GetRequiredService<TaskContext>();
SeedData.Initialize(context);
}
app.Run();
// SeedData.cs
public static class SeedData
{
public static void Initialize(TaskContext context)
{
if (context.Users.Any()) return;
var user1 = new User { Username = "alice", Email = "alice@example.com" };
var user2 = new User { Username = "bob", Email = "bob@example.com" };
var project1 = new Project
{
Name = "网站开发",
Description = "公司官网重构",
StartDate = DateTime.Now
};
context.Users.AddRange(user1, user2);
context.Projects.Add(project1);
context.SaveChanges();
var task1 = new TaskItem
{
Title = "设计首页UI",
Description = "使用Figma设计首页界面",
Status = TaskStatus.InProgress,
Priority = PriorityLevel.High,
DueDate = DateTime.Now.AddDays(7),
ProjectId = project1.Id,
AssignedToUserId = user1.Id
};
var task2 = new TaskItem
{
Title = "实现用户认证",
Description = "使用JWT实现登录注册",
Status = TaskStatus.Pending,
Priority = PriorityLevel.Critical,
DueDate = DateTime.Now.AddDays(3),
ProjectId = project1.Id,
AssignedToUserId = user2.Id
};
context.Tasks.AddRange(task1, task2);
context.SaveChanges();
}
}
第九章:单元测试与代码质量
9.1 使用xUnit进行单元测试
// 被测试的类
public class Calculator
{
public int Add(int a, int b) => a + b;
public int Subtract(int a, int b) => a - b;
public int Multiply(int a, int b) => a * b;
public double Divide(int a, int b)
{
if (b == 0) throw new DivideByZeroException();
return (double)a / b;
}
}
// 测试类
using Xunit;
public class CalculatorTests
{
private readonly Calculator _calculator;
public CalculatorTests()
{
_calculator = new Calculator();
}
[Fact]
public void Add_ShouldReturnSum_WhenGivenPositiveNumbers()
{
// Arrange
int a = 5;
int b = 3;
// Act
int result = _calculator.Add(a, b);
// Assert
Assert.Equal(8, result);
}
[Theory]
[InlineData(1, 2, 3)]
[InlineData(-1, 1, 0)]
[InlineData(0, 5, 5)]
public void Add_ShouldReturnCorrectSum(int a, int b, int expected)
{
int result = _calculator.Add(a, b);
Assert.Equal(expected, result);
}
[Fact]
public void Divide_ShouldThrowException_WhenDividingByZero()
{
Assert.Throws<DivideByZeroException>(() => _calculator.Divide(10, 0));
}
[Fact]
public void Divide_ShouldReturnCorrectResult()
{
double result = _calculator.Divide(10, 2);
Assert.Equal(5.0, result, precision: 2);
}
}
// 使用Moq进行Mock测试
using Moq;
public interface IEmailSender
{
bool Send(string to, string subject, string body);
}
public class NotificationManager
{
private readonly IEmailSender _emailSender;
public NotificationManager(IEmailSender emailSender)
{
_emailSender = emailSender;
}
public bool NotifyUser(string email, string message)
{
return _emailSender.Send(email, "通知", message);
}
}
public class NotificationManagerTests
{
[Fact]
public void NotifyUser_ShouldCallEmailSender()
{
// Arrange
var mockSender = new Mock<IEmailSender>();
mockSender.Setup(s => s.Send(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>()))
.Returns(true);
var manager = new NotificationManager(mockSender.Object);
// Act
bool result = manager.NotifyUser("test@example.com", "Hello");
// Assert
Assert.True(result);
mockSender.Verify(s => s.Send("test@example.com", "通知", "Hello"), Times.Once);
}
}
第十章:部署与性能优化
10.1 应用部署
// Dockerfile 示例
FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base
WORKDIR /app
EXPOSE 80
EXPOSE 443
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
WORKDIR /src
COPY ["TaskManager/TaskManager.csproj", "TaskManager/"]
RUN dotnet restore "TaskManager/TaskManager.csproj"
COPY . .
WORKDIR "/src/TaskManager"
RUN dotnet build "TaskManager.csproj" -c Release -o /app/build
FROM build AS publish
RUN dotnet publish "TaskManager.csproj" -c Release -o /app/publish
FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "TaskManager.dll"]
10.2 性能优化技巧
// 1. 异步编程最佳实践
public class AsyncOptimization
{
// ❌ 错误:同步阻塞
public string GetDataSync()
{
var result = DatabaseQuery(); // 阻塞线程
return result;
}
// ✅ 正确:异步非阻塞
public async Task<string> GetDataAsync()
{
var result = await DatabaseQueryAsync(); // 释放线程
return result;
}
// 2. 缓存策略
private readonly MemoryCache _cache = new MemoryCache(new MemoryCacheOptions());
public async Task<string> GetCachedData(string key)
{
return await _cache.GetOrCreateAsync(key, async entry =>
{
entry.AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(5);
return await ExpensiveDatabaseCall();
});
}
// 3. 批量操作
public async Task BulkInsertAsync(List<User> users)
{
// ❌ 逐条插入(慢)
foreach (var user in users)
{
await _context.Users.AddAsync(user);
await _context.SaveChangesAsync();
}
// ✅ 批量插入(快)
await _context.Users.AddRangeAsync(users);
await _context.SaveChangesAsync();
}
// 4. 查询优化
public async Task<List<TaskItem>> GetTasksOptimized()
{
// ❌ 加载所有数据到内存
return await _context.Tasks.ToListAsync();
// ✅ 只选择需要的字段
return await _context.Tasks
.Where(t => t.Status == TaskStatus.Pending)
.Select(t => new TaskItem { Id = t.Id, Title = t.Title })
.ToListAsync();
}
// 5. 使用ValueTask减少分配
public ValueTask<int> GetCachedValueAsync(int key)
{
if (_cache.TryGetValue(key, out int value))
{
// 已缓存,同步返回
return new ValueTask<int>(value);
}
// 未缓存,异步计算
return new ValueTask<int>(CalculateValueAsync(key));
}
}
第十一章:持续学习与职业发展
11.1 学习路线图
基础阶段(1-3个月)
- C#语法和OOP概念
- .NET基础类库
- 基本的数据结构和算法
- Git版本控制
进阶阶段(3-6个月)
- ASP.NET Core Web开发
- Entity Framework Core
- 异步编程和多线程
- 设计模式
高级阶段(6-12个月)
- 微服务架构
- 云原生开发(Azure/AWS)
- 容器化(Docker/Kubernetes)
- 性能优化和调试技巧
专业领域(12个月+)
- 特定行业解决方案
- 架构设计
- 技术领导力
11.2 实用资源
- 官方文档:docs.microsoft.com/dotnet
- 在线课程:Pluralsight, Udemy
- 开源项目:GitHub上的.NET项目
- 社区:Stack Overflow, Reddit r/dotnet
- 博客:Scott Hanselman, Jon Skeet
11.3 求职建议
- 构建作品集:在GitHub上展示你的项目
- 实习经验:即使是小项目也能积累经验
- 认证考试:考虑Microsoft认证(如AZ-204)
- 网络建设:参加技术社区活动
- 持续学习:技术更新快,保持学习热情
结语
恭喜你完成了从零基础到精通.NET的完整学习之旅!我们从环境搭建开始,逐步深入到C#基础语法、面向对象编程、高级特性、数据访问、Web开发、测试和部署等各个方面。
记住,编程是一门实践的艺术。理论知识固然重要,但真正的掌握来自于不断的编码实践。建议你:
- 动手实践:跟随本文的每个代码示例亲自运行
- 构建项目:尝试构建自己的项目,解决实际问题
- 阅读源码:学习优秀的开源项目代码
- 参与社区:提问、回答、分享你的知识
- 保持好奇:技术永无止境,保持学习的热情
.NET是一个强大而充满活力的平台,随着.NET 8及未来版本的发布,它将继续在云原生、AI集成、跨平台开发等领域发挥重要作用。现在,你已经具备了开启编程职业生涯的坚实基础。
祝你在.NET开发的道路上取得成功!
