C# 基础入门
C# 是 .NET 平台上最核心的语言之一。它既可以写 Web API,也能写桌面程序、后台服务、自动化工具,甚至还能做游戏开发。对后端开发者来说,学习 C# 的重点不是只会写几个语法示例,而是要逐步建立“类型系统 + 面向对象 + 集合处理 + 异步模型”的完整认知。
这篇文章会按照入门顺序,把最常见也最重要的基础内容串起来。
第一章 第一个 C# 程序与基本语法
1.1 一个最简单的控制台程序
Console.WriteLine("Hello, C#!");
如果你使用的是现代 .NET 模板,控制台项目通常默认启用了“顶级语句”,所以不一定一开始就看到传统的 Program 类和 Main 方法。
更完整一点的写法如下:
using System;
public class Program
{
public static void Main(string[] args)
{
Console.WriteLine("Hello, C#!");
}
}
这段代码里最值得先记住的点有三个:
using System;:引入命名空间Main:程序入口Console.WriteLine(...):向控制台输出内容
1.2 注释与命名
// 这是单行注释
/*
这是多行注释
*/
/// <summary>
/// 文档注释,常用于类和方法
/// </summary>
public class Demo
{
}
命名建议:
- 类名、方法名、属性名:使用 PascalCase,例如
UserService - 局部变量、参数:使用 camelCase,例如
userName - 常量:通常也用 PascalCase,例如
MaxRetryCount
第二章 变量、类型与类型系统基础
2.1 常见基本类型
C# 常见基础类型包括:
| 类型 | 说明 | 示例 |
|---|---|---|
int |
整数 | 18 |
long |
长整数 | 123456789L |
double |
双精度浮点数 | 3.14 |
decimal |
高精度小数,常用于金额 | 99.95m |
bool |
布尔值 | true |
char |
单个字符 | 'A' |
string |
字符串 | "hello" |
DateTime |
日期时间 | DateTime.Now |
示例:
int age = 20;
string name = "Tom";
decimal price = 199.99m;
bool isAdmin = false;
Console.WriteLine($"{name}, {age}, {price}, {isAdmin}");
2.2 var 不是弱类型
很多人刚学 C# 时会误以为 var 和 JavaScript 的 var 一样是动态类型,其实不是。
var count = 10;
var title = "dotnet";
这里的 count 在编译期仍然会被推断为 int,title 会被推断为 string。也就是说,C# 依然是强类型语言。
var 适合:
- 类型右侧已经很明显时
- 泛型类型名很长时
- 匿名对象场景
不适合:
- 让代码可读性变差时
2.3 值类型与引用类型
这是 C# 非常重要的基础概念。
- 值类型:
int、double、bool、struct、enum - 引用类型:
string、数组、类对象、委托
值类型示例
int a = 10;
int b = a;
b = 20;
Console.WriteLine(a); // 10
Console.WriteLine(b); // 20
引用类型示例
var user1 = new User { Name = "Alice" };
var user2 = user1;
user2.Name = "Bob";
Console.WriteLine(user1.Name); // Bob
Console.WriteLine(user2.Name); // Bob
public class User
{
public string Name { get; set; } = string.Empty;
}
它们的核心区别不在于“高级不高级”,而在于复制和传递时的行为不同。
2.4 可空类型
值类型默认不能为 null,但你可以通过 ? 声明可空值类型:
int? age = null;
DateTime? createdAt = null;
引用类型在现代 .NET 项目里通常会启用可空引用类型分析,例如:
string? nickName = null;
string userName = "admin";
这套机制的意义是尽量在编译阶段提前发现空引用风险。
第三章 运算符、流程控制与方法
3.1 常见运算符
int a = 10;
int b = 3;
Console.WriteLine(a + b); // 13
Console.WriteLine(a - b); // 7
Console.WriteLine(a * b); // 30
Console.WriteLine(a / b); // 3
Console.WriteLine(a % b); // 1
逻辑运算:
bool result1 = a > 5 && b < 10;
bool result2 = a < 5 || b < 10;
bool result3 = !false;
3.2 if、switch 与循环
if
int score = 86;
if (score >= 90)
{
Console.WriteLine("优秀");
}
else if (score >= 60)
{
Console.WriteLine("及格");
}
else
{
Console.WriteLine("不及格");
}
switch
int day = 2;
switch (day)
{
case 1:
Console.WriteLine("星期一");
break;
case 2:
Console.WriteLine("星期二");
break;
default:
Console.WriteLine("其他");
break;
}
现代 C# 也支持更简洁的 switch 表达式:
string text = day switch
{
1 => "星期一",
2 => "星期二",
_ => "其他"
};
循环
for (int i = 0; i < 3; i++)
{
Console.WriteLine(i);
}
int count = 0;
while (count < 3)
{
Console.WriteLine(count);
count++;
}
3.3 方法
方法用于封装一段可复用逻辑。
public static int Add(int a, int b)
{
return a + b;
}
var sum = Add(3, 5);
Console.WriteLine(sum);
方法重载指的是方法名相同,但参数列表不同:
public static int Add(int a, int b) => a + b;
public static double Add(double a, double b) => a + b;
第四章 类、对象与面向对象基础
4.1 类和对象
public class Student
{
public string Name { get; set; } = string.Empty;
public int Age { get; set; }
public void Study()
{
Console.WriteLine($"{Name} 正在学习");
}
}
使用对象:
var student = new Student
{
Name = "小明",
Age = 18
};
student.Study();
4.2 属性与字段
初学时经常会看到字段和属性,它们不是一回事。
public class Product
{
private decimal price; // 字段
public decimal Price // 属性
{
get { return price; }
set { price = value < 0 ? 0 : value; }
}
}
更常见的写法是自动属性:
public string Name { get; set; } = string.Empty;
4.3 构造方法
public class Order
{
public string OrderNo { get; }
public decimal Amount { get; }
public Order(string orderNo, decimal amount)
{
OrderNo = orderNo;
Amount = amount;
}
}
创建对象:
var order = new Order("NO001", 120.5m);
4.4 封装、继承、多态
封装
通过属性、访问修饰符控制对象状态。
继承
public class Animal
{
public string Name { get; set; } = string.Empty;
public virtual void Speak()
{
Console.WriteLine("动物发声");
}
}
public class Dog : Animal
{
public override void Speak()
{
Console.WriteLine("汪汪");
}
}
多态
Animal animal = new Dog();
animal.Speak(); // 汪汪
多态的核心价值在于:统一抽象,运行时由具体实现决定行为。
4.5 接口
接口更适合表示“能力约定”。
public interface IUserService
{
string GetUserName(int id);
}
public class UserService : IUserService
{
public string GetUserName(int id)
{
return $"user-{id}";
}
}
在真实项目中,接口经常和依赖注入一起使用。
第五章 集合、泛型与 LINQ
5.1 常见集合
C# 项目里最常用的集合有:
List<T>:有序集合Dictionary<TKey, TValue>:键值对HashSet<T>:去重集合- 数组:固定长度集合
示例:
var names = new List<string> { "Alice", "Bob", "Tom" };
foreach (var name in names)
{
Console.WriteLine(name);
}
5.2 泛型为什么重要
泛型可以让代码复用,同时保证类型安全。
public class Repository<T>
{
private readonly List<T> items = new();
public void Add(T item)
{
items.Add(item);
}
public List<T> GetAll()
{
return items;
}
}
5.3 LINQ
LINQ 是 C# 非常强大的查询能力,平时写集合处理、数据库查询、投影转换时会高频使用。
var numbers = new List<int> { 1, 2, 3, 4, 5, 6 };
var result = numbers
.Where(x => x > 3)
.Select(x => x * 10)
.OrderBy(x => x)
.ToList();
常用操作:
Where:过滤Select:投影OrderBy/OrderByDescending:排序FirstOrDefault:取第一项Any:判断是否存在Count:统计数量GroupBy:分组
一个更接近业务的例子
var users = new List<UserDto>
{
new() { Id = 1, Name = "Tom", IsActive = true },
new() { Id = 2, Name = "Alice", IsActive = false },
new() { Id = 3, Name = "Bob", IsActive = true }
};
var activeUsers = users
.Where(x => x.IsActive)
.Select(x => new { x.Id, x.Name })
.ToList();
public class UserDto
{
public int Id { get; set; }
public string Name { get; set; } = string.Empty;
public bool IsActive { get; set; }
}
第六章 字符串、时间与常见基础能力
6.1 字符串处理
string name = " dotnet ";
Console.WriteLine(name.Trim());
Console.WriteLine(name.ToUpper());
Console.WriteLine(name.Contains("net"));
字符串拼接常见方式:
string userName = "Tom";
int age = 20;
string text1 = userName + " 的年龄是 " + age;
string text2 = $"{userName} 的年龄是 {age}";
实际开发里更推荐字符串插值:
$"{userName} 的年龄是 {age}"
6.2 时间处理
DateTime now = DateTime.Now;
DateTime utcNow = DateTime.UtcNow;
Console.WriteLine(now.ToString("yyyy-MM-dd HH:mm:ss"));
Console.WriteLine(now.AddDays(7));
时间处理常见坑:
- 本地时间和 UTC 混用
- 格式化写法不统一
- 数据库存储时区不明确
第七章 异常处理与资源释放
7.1 try-catch-finally
try
{
var content = File.ReadAllText("appsettings.json");
Console.WriteLine(content);
}
catch (Exception ex)
{
Console.WriteLine($"读取失败: {ex.Message}");
}
finally
{
Console.WriteLine("执行结束");
}
异常处理的重点不是“把所有代码包起来”,而是:
- 只捕获你能处理的异常
- 不要无声吞掉异常
- 记录必要日志
- 区分业务异常和系统异常
7.2 using 与资源释放
很多资源需要及时释放,比如文件流、数据库连接、网络流。
using var stream = new FileStream("demo.txt", FileMode.OpenOrCreate);
using var writer = new StreamWriter(stream);
writer.WriteLine("hello");
using 的意义是让对象在使用结束后自动调用 Dispose()。
第八章 委托、Lambda 与事件
8.1 委托
委托可以理解成“方法的类型”。
public delegate int Calc(int a, int b);
static int Add(int a, int b) => a + b;
Calc calc = Add;
Console.WriteLine(calc(2, 3));
在现代开发中,手写自定义委托并不是最多的,更常见的是:
ActionFunc<T>- Lambda 表达式
8.2 Lambda
Func<int, int, int> add = (a, b) => a + b;
Console.WriteLine(add(3, 4));
LINQ、事件回调、异步编程里都会高频出现 Lambda。
8.3 事件
事件本质上是建立在委托之上的发布订阅模型。
public class OrderService
{
public event Action<string>? OrderCreated;
public void Create(string orderNo)
{
Console.WriteLine($"创建订单: {orderNo}");
OrderCreated?.Invoke(orderNo);
}
}
第九章 async / await 与异步编程
9.1 为什么要学异步
在后端开发里,下面这些操作都非常常见:
- 数据库访问
- HTTP 请求
- 文件读写
- 缓存访问
它们很多都是 IO 密集型操作,适合用异步方式避免线程长时间阻塞。
9.2 最基础的异步示例
public async Task<string> GetDataAsync()
{
await Task.Delay(300);
return "ok";
}
调用:
string result = await GetDataAsync();
Console.WriteLine(result);
9.3 Task 和 Task<T>
Task:表示无返回值的异步操作Task<T>:表示有返回值的异步操作
public async Task SaveAsync()
{
await Task.Delay(100);
}
public async Task<int> GetCountAsync()
{
await Task.Delay(100);
return 10;
}
9.4 异步编程的常见误区
不要滥用 async void
除事件处理器外,通常不要写 async void,否则异常难以管理。
不要为了异步而异步
纯 CPU 计算逻辑不一定要强行改成异步。
IO 场景优先考虑异步 API
例如:
ReadAllTextAsyncToListAsyncSendAsync
第十章 初学者常见问题
10.1 string 为什么是引用类型,但看起来像值类型
因为字符串不可变,所以很多时候它表现得很像值,但本质上它仍然是引用类型。
10.2 List<T> 和数组怎么选
- 长度固定,结构简单:数组
- 需要动态增删:
List<T>
10.3 null 为什么这么容易出问题
因为真实业务里很多数据天然就可能为空,所以要重视:
- 可空分析
- 判空逻辑
- 防御式编程
10.4 为什么感觉 LINQ 很好用,但又怕性能问题
LINQ 本身不是问题,关键是:
- 你是否知道它什么时候执行
- 你是否重复枚举
- 在数据库查询里是否生成了低效 SQL
第十一章 建议的入门顺序
学习 C# 时,推荐按下面顺序推进:
- 变量、类型、流程控制、方法
- 类、对象、属性、构造方法
- 封装、继承、接口、多态
- 集合、泛型、
LINQ - 字符串、时间、文件、异常
- 委托、Lambda、事件
Task、async / await
学到这一步时,你就已经具备进入 .NET Web 项目开发的语言基础了。
下一步阅读
- 如果你想继续补齐数据处理能力,阅读
C# 集合与 LINQ 实战 - 如果你想进入
.NET工程和项目组织层面,阅读.NET CLI 与项目结构 - 如果你想把这些语言能力用到 Web 项目里,阅读
ASP.NET Core 基础
本文小结
学习 C# 的关键不是“会写语法题”,而是逐步理解这几条主线:
- 类型系统决定数据如何被表达和传递
- 面向对象决定代码如何组织
- 集合和
LINQ决定数据如何处理 - 异常与资源释放决定程序是否稳定
- 异步模型决定后端程序是否高效
只要把这几条主线打稳,后续学习 ASP.NET Core、EF Core 和真实业务项目时就会顺畅很多。