C# 基础入门

系统整理 C# 基础知识,覆盖语法、类型系统、面向对象、集合、LINQ、异常、委托和异步编程。

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 在编译期仍然会被推断为 inttitle 会被推断为 string。也就是说,C# 依然是强类型语言。

var 适合:

  • 类型右侧已经很明显时
  • 泛型类型名很长时
  • 匿名对象场景

不适合:

  • 让代码可读性变差时

2.3 值类型与引用类型

这是 C# 非常重要的基础概念。

  • 值类型:intdoubleboolstructenum
  • 引用类型: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 ifswitch 与循环

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

LINQC# 非常强大的查询能力,平时写集合处理、数据库查询、投影转换时会高频使用。

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));

在现代开发中,手写自定义委托并不是最多的,更常见的是:

  • Action
  • Func<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 TaskTask<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

例如:

  • ReadAllTextAsync
  • ToListAsync
  • SendAsync

第十章 初学者常见问题

10.1 string 为什么是引用类型,但看起来像值类型

因为字符串不可变,所以很多时候它表现得很像值,但本质上它仍然是引用类型。

10.2 List<T> 和数组怎么选

  • 长度固定,结构简单:数组
  • 需要动态增删:List<T>

10.3 null 为什么这么容易出问题

因为真实业务里很多数据天然就可能为空,所以要重视:

  • 可空分析
  • 判空逻辑
  • 防御式编程

10.4 为什么感觉 LINQ 很好用,但又怕性能问题

LINQ 本身不是问题,关键是:

  • 你是否知道它什么时候执行
  • 你是否重复枚举
  • 在数据库查询里是否生成了低效 SQL

第十一章 建议的入门顺序

学习 C# 时,推荐按下面顺序推进:

  1. 变量、类型、流程控制、方法
  2. 类、对象、属性、构造方法
  3. 封装、继承、接口、多态
  4. 集合、泛型、LINQ
  5. 字符串、时间、文件、异常
  6. 委托、Lambda、事件
  7. Taskasync / await

学到这一步时,你就已经具备进入 .NET Web 项目开发的语言基础了。


下一步阅读


本文小结

学习 C# 的关键不是“会写语法题”,而是逐步理解这几条主线:

  • 类型系统决定数据如何被表达和传递
  • 面向对象决定代码如何组织
  • 集合和 LINQ 决定数据如何处理
  • 异常与资源释放决定程序是否稳定
  • 异步模型决定后端程序是否高效

只要把这几条主线打稳,后续学习 ASP.NET CoreEF Core 和真实业务项目时就会顺畅很多。