引言:为什么选择.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代码之前,我们需要先搭建开发环境。对于初学者,推荐安装以下工具:

  1. .NET SDK:这是.NET开发的核心,包含了编译器、运行时和命令行工具。

  2. 开发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中,有效的调试技巧可以大大提高开发效率:

  1. 断点设置

    • 条件断点:右键断点 → 条件 → 输入表达式(如 x > 100
    • 断点操作:可以记录日志而不中断执行
    • 函数断点:在函数入口处设置断点
  2. 监视窗口

    • 添加监视表达式
    • 实时查看变量变化
    • 查看对象的所有属性
  3. 即时窗口

    • 执行代码片段
    • 修改变量值
    • 调用方法
  4. 调用堆栈

    • 查看方法调用链
    • 快速导航到上层调用
  5. 内存分析

    • 使用内存分析器查找内存泄漏
    • 分析对象分配情况

第六章:数据访问与数据库操作

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. 基础阶段(1-3个月)

    • C#语法和OOP概念
    • .NET基础类库
    • 基本的数据结构和算法
    • Git版本控制
  2. 进阶阶段(3-6个月)

    • ASP.NET Core Web开发
    • Entity Framework Core
    • 异步编程和多线程
    • 设计模式
  3. 高级阶段(6-12个月)

    • 微服务架构
    • 云原生开发(Azure/AWS)
    • 容器化(Docker/Kubernetes)
    • 性能优化和调试技巧
  4. 专业领域(12个月+)

    • 特定行业解决方案
    • 架构设计
    • 技术领导力

11.2 实用资源

  • 官方文档:docs.microsoft.com/dotnet
  • 在线课程:Pluralsight, Udemy
  • 开源项目:GitHub上的.NET项目
  • 社区:Stack Overflow, Reddit r/dotnet
  • 博客:Scott Hanselman, Jon Skeet

11.3 求职建议

  1. 构建作品集:在GitHub上展示你的项目
  2. 实习经验:即使是小项目也能积累经验
  3. 认证考试:考虑Microsoft认证(如AZ-204)
  4. 网络建设:参加技术社区活动
  5. 持续学习:技术更新快,保持学习热情

结语

恭喜你完成了从零基础到精通.NET的完整学习之旅!我们从环境搭建开始,逐步深入到C#基础语法、面向对象编程、高级特性、数据访问、Web开发、测试和部署等各个方面。

记住,编程是一门实践的艺术。理论知识固然重要,但真正的掌握来自于不断的编码实践。建议你:

  1. 动手实践:跟随本文的每个代码示例亲自运行
  2. 构建项目:尝试构建自己的项目,解决实际问题
  3. 阅读源码:学习优秀的开源项目代码
  4. 参与社区:提问、回答、分享你的知识
  5. 保持好奇:技术永无止境,保持学习的热情

.NET是一个强大而充满活力的平台,随着.NET 8及未来版本的发布,它将继续在云原生、AI集成、跨平台开发等领域发挥重要作用。现在,你已经具备了开启编程职业生涯的坚实基础。

祝你在.NET开发的道路上取得成功!