C#教程(2024最新):基础、进阶与实战
C# 教程 (2024 最新):基础、进阶与实战
C# (读作 "C Sharp") 是由微软开发的一种现代、通用、面向对象的编程语言。它以其强大的功能、类型安全、以及与 .NET 生态系统的紧密集成而闻名。无论你是编程新手还是希望扩展技能的经验丰富的开发者,本教程都将带你从基础到进阶,最终通过实战项目掌握 C# 编程。
一、基础篇:C# 入门
1.1 开发环境搭建
- Visual Studio (推荐): 微软官方提供的集成开发环境 (IDE),提供代码编辑、调试、编译、项目管理等全方位支持。下载 Visual Studio Community (免费版) 即可满足学习需求。 安装时,务必勾选 ".NET desktop development" 工作负载。
- Visual Studio Code: 轻量级、跨平台的代码编辑器,配合 C# 扩展 (OmniSharp) 也能提供良好的开发体验。需要单独安装 .NET SDK。
- .NET SDK: 包含 C# 编译器、运行时 (CLR) 和基础类库。 可以从微软官网下载。
验证安装: 打开命令行 (Windows) 或终端 (macOS/Linux),输入 dotnet --version
,如果显示 .NET SDK 版本号,则表示安装成功。
1.2 第一个 C# 程序: "Hello, World!"
```csharp
using System;
namespace HelloWorld
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Hello, World!");
}
}
}
```
using System;
: 导入System
命名空间,其中包含常用的类 (如Console
)。namespace HelloWorld
: 定义一个命名空间,用于组织代码,避免命名冲突。class Program
: 定义一个名为Program
的类。 C# 程序通常从一个包含Main
方法的类开始执行。static void Main(string[] args)
: 程序的入口点。static
表示该方法属于类本身,而不是类的实例。void
表示该方法不返回值。string[] args
用于接收命令行参数 (可选)。Console.WriteLine("Hello, World!");
: 调用Console
类的WriteLine
方法,在控制台输出文本。
编译和运行:
- 使用 Visual Studio: 创建新项目 (Console App),粘贴代码,点击 "Start" 或按 F5 键。
- 使用 .NET CLI: 将代码保存为
Program.cs
文件, 打开命令行,导航到文件所在目录,执行以下命令:
bash
dotnet build # 编译
dotnet run # 运行
1.3 C# 基础语法
- 变量和数据类型:
- 基本数据类型:
int
(整数),float
(单精度浮点数),double
(双精度浮点数),bool
(布尔值,true
或false
),char
(字符),string
(字符串)。 - 变量声明:
数据类型 变量名 = 值;
(例如:int age = 30;
) - 类型推断 (var):
var name = "Alice";
(编译器根据初始值自动推断类型)。
- 基本数据类型:
- 运算符:
- 算术运算符:
+
,-
,*
,/
,%
(取模)。 - 关系运算符:
==
(等于),!=
(不等于),>
,<
,>=
,<=
. - 逻辑运算符:
&&
(与),||
(或),!
(非)。 - 赋值运算符:
=
,+=
,-=
,*=
,/=
,%=
。 - 条件运算符 (三元运算符):
条件 ? 表达式1 : 表达式2
(如果条件为真,返回表达式1的值,否则返回表达式2的值)。
- 算术运算符:
- 控制流:
if-else
语句: 根据条件执行不同的代码块。
csharp
if (age >= 18)
{
Console.WriteLine("成年");
}
else
{
Console.WriteLine("未成年");
}switch
语句: 根据表达式的值执行不同的代码块。
csharp
switch (dayOfWeek)
{
case 1:
Console.WriteLine("星期一");
break;
case 2:
Console.WriteLine("星期二");
break;
// ... 其他 case
default:
Console.WriteLine("无效的星期");
break;
}for
循环: 重复执行一段代码,指定循环次数。
csharp
for (int i = 0; i < 10; i++)
{
Console.WriteLine(i);
}while
循环: 当条件为真时,重复执行一段代码。
csharp
int count = 0;
while (count < 5)
{
Console.WriteLine(count);
count++;
}do-while
循环: 至少执行一次代码块,然后当条件为真时重复执行。
csharp
int num = 1;
do
{
Console.WriteLine(num);
num++;
} while (num <= 3);break
和continue
语句:break
用于跳出循环,continue
用于跳过当前循环迭代,继续下一次迭代。
- 注释:
- 单行注释:
// 这是单行注释
- 多行注释:
/* 这是多行注释 */
- 文档注释:
/// <summary>这是方法的文档注释</summary>
(用于生成 API 文档)
- 单行注释:
1.4 数组、集合和字符串
- 数组 (Array): 存储固定大小的相同类型元素的集合。
csharp
int[] numbers = new int[5]; // 创建一个包含 5 个整数的数组
numbers[0] = 10; // 访问和修改数组元素
int firstNumber = numbers[0]; - 集合 (Collections): 提供更灵活的数据存储方式 (动态大小、不同类型元素等)。
List<T>
(列表): 有序、可变大小的集合。
csharp
List<string> names = new List<string>();
names.Add("Bob");
names.Add("Charlie");
string secondName = names[1];Dictionary<TKey, TValue>
(字典): 键值对集合,通过键快速查找值。
csharp
Dictionary<string, int> ages = new Dictionary<string, int>();
ages["Alice"] = 25;
ages["David"] = 35;
int aliceAge = ages["Alice"];HashSet<T>
(集合): 无序、不重复元素的集合。Queue<T>
(队列): 先进先出 (FIFO) 集合。Stack<T>
(栈): 后进先出 (LIFO) 集合。
- 字符串 (String):
- 字符串插值:
$"My name is {name} and I am {age} years old."
(更简洁的字符串拼接方式)。 - 常用字符串方法:
Length
(长度),Substring
(截取子串),IndexOf
(查找子串),Replace
(替换),ToUpper
(转大写),ToLower
(转小写),Trim
(去除首尾空白字符)。 - StringBuilder: 对于频繁修改的字符串,使用
StringBuilder
类可以提高性能,因为它避免了创建多个字符串对象的开销。
- 字符串插值:
1.5 枚举 (Enums)
-
枚举是一种值类型,用于定义一组命名的整数常量。
```csharp
enum DaysOfWeek
{
Monday, // 默认值为 0
Tuesday, // 1
Wednesday, // 2
Thursday, // 3
Friday, // 4
Saturday, // 5
Sunday // 6
}DaysOfWeek today = DaysOfWeek.Wednesday;
// 可以将枚举值转换为整数,反之亦然
int dayValue = (int)today; // dayValue = 2
DaysOfWeek tomorrow = (DaysOfWeek)3; // tomorrow = DaysOfWeek.Thursday//可以自定义枚举值
enum ErrorCodes
{
None = 0,
NotFound = 404,
BadRequest = 400,
Unauthorized = 401
}
```
二、进阶篇:面向对象编程 (OOP)
2.1 类和对象
- 类 (Class): 对象的蓝图或模板,定义了对象的属性 (数据) 和方法 (行为)。
```csharp
class Dog
{
// 属性 (字段)
public string Name;
public string Breed;
public int Age;// 方法 public void Bark() { Console.WriteLine("Woof!"); } public void Eat(string food) { Console.WriteLine($"{Name} is eating {food}."); }
}
* **对象 (Object):** 类的实例,具有类定义的属性和方法。
csharp
Dog myDog = new Dog(); // 创建 Dog 类的实例
myDog.Name = "Buddy";
myDog.Breed = "Golden Retriever";
myDog.Age = 3;
myDog.Bark(); // 调用方法
myDog.Eat("kibble");
```
2.2 构造函数
-
构造函数 (Constructor): 用于初始化对象的特殊方法,与类同名,没有返回值类型。
```csharp
class Cat
{
public string Name;
public string Color;// 构造函数 public Cat(string name, string color) { Name = name; Color = color; } //无参数构造函数 public Cat() { Name = "unnamed"; Color = "unknown" } // 可以有多个构造函数 (重载) public Cat(string name) : this(name, "Unknown") { } //调用上面的双参数构造函数.
}
Cat myCat = new Cat("Whiskers", "Gray"); // 使用构造函数创建对象
Cat anotherCat = new Cat("Tom"); //使用重载的单参数构造函数
Cat namelessCat = new Cat(); //使用无参数构造函数
```
2.3 封装 (Encapsulation)
- 访问修饰符:
public
(公开, 任何地方都可以访问),private
(私有, 只能在类内部访问),protected
(受保护, 只能在类内部和派生类中访问),internal
(内部, 只能在同一程序集中访问)。 - 属性 (Properties): 提供对类字段的受控访问。 属性通常包含
get
(读取) 和set
(写入) 访问器。
```csharp
class Person
{
private string _name; // 私有字段public string Name // 公开属性 { get { return _name; } set { if (!string.IsNullOrEmpty(value)) { _name = value; } } } // 自动实现的属性 (简写形式) public int Age { get; set; } //只读属性 public string FullName {get;} = "John Doe";
}
```
2.4 继承 (Inheritance)
-
继承: 允许一个类 (子类/派生类) 从另一个类 (父类/基类) 继承属性和方法,实现代码重用和层次结构。
```csharp
// 基类 (父类)
class Animal
{
public string Name { get; set; }public virtual void MakeSound() // 虚方法, 允许子类重写 { Console.WriteLine("Generic animal sound"); }
}
// 派生类 (子类)
class Dog : Animal
{
public string Breed { get; set; }// 重写 (override) 父类的方法 public override void MakeSound() { Console.WriteLine("Woof!"); }
}
//派生类 (子类)
class Cat : Animal
{
public string Color {get; set;}
//重写 (override) 父类方法
public override void MakeSound()
{
Console.WriteLine("Meow!");
}
}
```
2.5 多态 (Polymorphism)
-
多态: 允许使用父类类型的变量引用子类对象,并在运行时调用子类的方法 (动态绑定)。
```csharp
Animal myAnimal = new Dog(); // 父类变量引用子类对象
myAnimal.MakeSound(); // 输出 "Woof!" (调用 Dog 类的 MakeSound 方法)myAnimal = new Cat();
myAnimal.MakeSound(); //输出 "Meow!" (调用 Cat 类的 MakeSound方法)
```
2.6 抽象类和接口
-
抽象类 (Abstract Class): 不能实例化的类,用于定义派生类必须实现的抽象成员 (抽象方法和抽象属性)。
```csharp
abstract class Shape
{
public abstract double Area { get; } // 抽象属性
public abstract void Draw(); // 抽象方法
}class Circle : Shape
{
public double Radius { get; set; }public override double Area { get { return Math.PI * Radius * Radius; } } public override void Draw() { Console.WriteLine("Drawing a circle"); }
}
* **接口 (Interface):** 定义一组方法、属性、事件和索引器的契约,类可以实现多个接口。
csharp
interface IPrintable
{
void Print();
}interface ILoggable
{
void Log(string message);
}class Document : IPrintable, ILoggable
{
public void Print()
{
Console.WriteLine("Printing document...");
}public void Log(string message) { Console.WriteLine($"Log: {message}"); }
}
```
2.7 泛型 (Generics)
-
泛型允许编写可重用的代码,处理不同类型的数据,而无需为每种类型编写单独的代码。
```csharp
class MyList// T 是类型参数
{
private T[] _items;
private int _count;public MyList(int capacity) { _items = new T[capacity]; _count = 0; } public void Add(T item) { _items[_count] = item; _count++; } public T GetItem(int index) { return _items[index]; }
}
MyList
intList = new MyList (10);
intList.Add(5);
int number = intList.GetItem(0);MyList
stringList = new MyList (5);
stringList.Add("Hello");
string text = stringList.GetItem(0);
* 常用的泛型集合: `List<T>`, `Dictionary<TKey, TValue>`, `HashSet<T>`, `Queue<T>`, `Stack<T>`.
csharp
* 泛型约束: 可以使用 `where` 子句对类型参数进行约束。
//约束T必须是引用类型
public void MyMethod(T value) where T : class
{
//...
}
//约束T必须是值类型
public void MyMethod2(T value) where T: struct
{}
//约束T必须实现IComparable接口
public void MyMethod3(T value) where T : IComparable
{}
```
2.8 委托 (Delegates) 和事件 (Events)
-
委托 (Delegate): 类型安全的函数指针,可以引用具有相同签名的方法。
```csharp
delegate void MyDelegate(string message); // 定义委托类型class Messenger
{
public void SendMessage(string message, MyDelegate callback)
{
Console.WriteLine($"Sending message: {message}");
callback(message); // 调用委托
}
}class Logger
{
public static void LogMessage(string message)
{
Console.WriteLine($"Log: {message}");
}
}// 使用委托
Messenger messenger = new Messenger();
messenger.SendMessage("Hello, world!", Logger.LogMessage); // 传递方法作为委托参数//匿名方法
messenger.SendMessage("Test Anonymous", delegate(string msg){
Console.WriteLine($"Anonymous method received: {msg}");
});
* **事件 (Event):** 基于委托的机制,允许对象在特定事件发生时通知其他对象。
csharp
class Button
{
// 定义事件 (基于委托)
public event EventHandler Click;// 触发事件的方法 protected virtual void OnClick() { Click?.Invoke(this, EventArgs.Empty); // 使用 ?. 运算符安全地调用事件 (如果事件有订阅者) } //模拟点击 public void SimulateClick() { OnClick(); }
}
class Form
{
public Form(Button button)
{
// 订阅事件
button.Click += Button_Click; // 使用 += 运算符订阅事件, 使用 -= 运算符取消订阅
}// 事件处理程序 (方法) private void Button_Click(object sender, EventArgs e) { Console.WriteLine("Button clicked!"); }
}
//使用
Button myButton = new Button();
Form myForm = new Form(myButton);
myButton.SimulateClick();
```
2.9 Lambda 表达式
-
Lambda 表达式是创建匿名方法(没有名称的方法)的简洁方式,通常用于委托和 LINQ 查询。
```csharp
// 使用 lambda 表达式创建委托
MyDelegate myDelegate = (message) => Console.WriteLine($"Lambda: {message}");
myDelegate("Hello from lambda");// 在 LINQ 中使用 lambda 表达式
Listnumbers = new List { 1, 2, 3, 4, 5 };
var evenNumbers = numbers.Where(n => n % 2 == 0); // 筛选偶数
foreach (int num in evenNumbers) { Console.WriteLine(num); }
``
(参数列表) => 表达式或语句块
* Lambda表达式语法:* 如果没有参数,使用空括号
()。
{}
* 如果只有一个参数,可以省略括号。
* 如果表达式或语句块只有一行,可以省略大括号和
return` 关键字。
三、实战篇:项目开发
3.1 LINQ (Language Integrated Query)
-
LINQ 是一种强大的查询语言,可以用于查询各种数据源 (集合、数组、数据库、XML 等)。
```csharp
Listnumbers = new List { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; // 查询表达式语法 (Query Expression Syntax)
var query = from n in numbers
where n > 5
orderby n descending
select n;// 方法语法 (Method Syntax)
var method = numbers.Where(n => n > 5).OrderByDescending(n => n);foreach (int num in query) // 或者 method
{
Console.WriteLine(num);
}
``
Where
* 常用的 LINQ 方法:(筛选),
Select(投影),
OrderBy(排序),
OrderByDescending(降序排序),
GroupBy(分组),
Join(连接),
FirstOrDefault(获取第一个元素或默认值),
ToList(转换为列表),
ToArray(转换为数组),
Count(计数),
Sum(求和),
Average(平均值),
Min(最小值),
Max` (最大值)。
3.2 异步编程 (async/await)
-
异步编程允许程序在执行耗时操作 (如网络请求、文件 I/O) 时不会阻塞主线程,提高程序的响应性。
```csharp
async TaskDownloadWebPageAsync(string url)
{
using (HttpClient client = new HttpClient())
{
// await 关键字用于等待异步操作完成,并获取结果
string result = await client.GetStringAsync(url);
return result;
}
}// 调用异步方法
async Task ProcessWebPageAsync()
{
string url = "https://www.example.com";
string content = await DownloadWebPageAsync(url); // await 关键字用于等待异步方法完成
Console.WriteLine($"Downloaded {content.Length} characters from {url}");
}
//在Main函数中调用 (需要将Main函数也标记为async)
static async Task Main(string[] args)
{
await ProcessWebPageAsync();
Console.ReadKey(); //防止控制台关闭
}
``
async
*关键字用于标记异步方法。
await
*关键字用于等待异步操作完成,并获取结果。
await只能在
async方法中使用。
Task
* 异步方法的返回值通常是(无返回值) 或
Task(有返回值)。
Task.Run` 方法可以将同步方法转换为异步任务。
* 使用
3.3 文件 I/O
-
C# 提供了丰富的类用于文件读写操作。
```csharp
using System.IO;// 写入文本文件
string filePath = "myFile.txt";
string text = "Hello, file I/O!";
File.WriteAllText(filePath, text);// 读取文本文件
string content = File.ReadAllText(filePath);
Console.WriteLine(content);//逐行读取
using (StreamReader reader = new StreamReader(filePath))
{
string line;
while ((line = reader.ReadLine()) != null)
{
Console.WriteLine(line);
}
}
//逐行写入
using (StreamWriter writer = new StreamWriter(filePath))
{
writer.WriteLine("Line 1");
writer.WriteLine("Line 2");
}
//二进制读写
using (BinaryWriter writer = new BinaryWriter(File.Open(filePath, FileMode.Create)))
{
writer.Write(123);
writer.Write("hello");
}
using (BinaryReader reader = new BinaryReader(File.Open(filePath,FileMode.Open)))
{
int num = reader.ReadInt32();
string str = reader.ReadString();
}// 使用 using 语句可以确保文件资源在使用后被正确释放 (即使发生异常)
``
File
* 常用的文件 I/O 类:(静态方法, 用于处理文件),
StreamReader(读取文本文件),
StreamWriter(写入文本文件),
BinaryReader(读取二进制文件),
BinaryWriter(写入二进制文件),
Directory(处理目录),
FileInfo(文件信息),
DirectoryInfo` (目录信息)。
3.4 异常处理 (try-catch-finally)
- 异常处理用于处理程序运行时可能发生的错误,防止程序崩溃。
csharp
try
{
// 可能引发异常的代码
int result = 10 / 0; // 除以零会引发 DivideByZeroException
}
catch (DivideByZeroException ex)
{
// 捕获特定类型的异常
Console.WriteLine($"Error: {ex.Message}");
}
catch (Exception ex)
{
// 捕获其他类型的异常
Console.WriteLine($"An unexpected error occurred: {ex.Message}");
}
finally
{
// 无论是否发生异常,都会执行的代码 (用于资源清理等)
Console.WriteLine("Finally block executed.");
}
//抛出异常
void MyMethod(int value)
{
if(value < 0)
{
throw new ArgumentOutOfRangeException("value","Value cannot be negative.");
}
}try
块包含可能引发异常的代码。catch
块用于捕获和处理特定类型的异常。可以有多个catch
块。finally
块包含无论是否发生异常,都会执行的代码。throw
关键字用于手动引发异常。Exception
类是所有异常类的基类。
3.5 Entity Framework Core (EF Core) (简要介绍)
- EF Core 是一个对象关系映射器 (ORM),简化了数据库访问。它允许你使用 C# 对象来操作数据库,而无需编写大量的 SQL 代码。
- 安装 EF Core NuGet 包:
Microsoft.EntityFrameworkCore
,Microsoft.EntityFrameworkCore.SqlServer
(或其他数据库提供程序),Microsoft.EntityFrameworkCore.Tools
(用于数据库迁移)。 - 定义实体类 (Entity Class):
csharp
public class Product
{
public int Id { get; set; }
public string Name { get; set; }
public decimal Price { get; set; }
} -
定义 DbContext:
```csharp
public class MyDbContext : DbContext
{
public DbSetProducts { get; set; } // DbSet 表示数据库中的表 protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { optionsBuilder.UseSqlServer("Server=(localdb)\\mssqllocaldb;Database=MyDatabase;Trusted_Connection=True;"); // 替换为你的数据库连接字符串 }
}
* 数据库迁移:
csharp
* `Add-Migration InitialCreate` (创建初始迁移)
* `Update-Database` (应用迁移到数据库)
* 使用 LINQ 查询数据库:
using (var context = new MyDbContext())
{
// 添加数据
var newProduct = new Product { Name = "Laptop", Price = 1200 };
context.Products.Add(newProduct);
context.SaveChanges(); // 保存更改到数据库// 查询数据
var products = context.Products.Where(p => p.Price > 1000).ToList();
foreach (var product in products)
{
Console.WriteLine($"Id: {product.Id}, Name: {product.Name}, Price: {product.Price}");
}
}
```
3.6 ASP.NET Core (简要介绍)
-
ASP.NET Core 是一个跨平台、高性能的框架,用于构建 Web 应用程序、API 和微服务。
-
创建新项目:
dotnet new webapi -n MyWebApi
(创建 Web API 项目)。 -
控制器 (Controller):
C#
[ApiController]
[Route("[controller]")]
public class ProductsController : ControllerBase
{
[HttpGet]
public IEnumerable<Product> Get()
{
//从数据库中,或者其他数据源中获取数据。
return new List<Product>
{
new Product { Id = 1, Name = "Product 1", Price = 10 },
new Product { Id = 2, Name = "Product 2", Price = 20 }
};
}
} -
启动项目:
dotnet run
-
访问 API: 使用浏览器或 API 测试工具 (如 Postman) 访问
https://localhost:<port>/products
(端口号在Properties/launchSettings.json
文件中)。
学习资源
- 微软官方文档: https://learn.microsoft.com/en-us/dotnet/csharp/
- C# 12 and .NET 8 – Modern Cross-Platform Development Fundamentals: https://www.packtpub.com/product/c-12-and-net-8-modern-cross-platform-development-fundamentals-eighth-edition/9781837638526
- C# in Depth, Fourth Edition: https://www.manning.com/books/c-sharp-in-depth-fourth-edition
总结
本教程提供了 C# 编程的全面指南,从基础语法到面向对象编程,再到实战项目开发。通过学习和实践,你将能够掌握 C# 编程技能,构建各种类型的应用程序。记住,持续学习和实践是掌握任何编程语言的关键。祝你编程愉快!