编码 · 编程语言
C# 入门教程(零基础)
简短回答
C# 是微软推出的静态类型、面向对象语言,运行在 .NET 上;.NET 是免费的跨平台运行时,支持 Windows、macOS 和 Linux。安装 .NET SDK,运行 dotnet new console,再 dotnet run 就会输出“Hello, World!”。核心概念包括:类与 record、List<T> 和 Dictionary<K, V> 等泛型集合、LINQ 查询、async/await、模式匹配和异常。
C# 是什么,用来做什么
C#(读作“C sharp”)由微软以 Anders Hejlsberg 为首的团队设计,2002 年首次发布。它由 Ecma 标准化(ECMA-334),并与 .NET 一起开源开发。C# 用于 Web API 和网站(ASP.NET Core)、Windows 桌面应用、跨平台移动与桌面应用(.NET MAUI)、云服务和游戏:Unity 引擎使用 C# 编写游戏脚本。它的语法属于 C 家族,Java、C++ 和 JavaScript 开发者会觉得很眼熟。
安装 .NET 并运行 Hello, world
从 dot.net 下载 .NET SDK,并用 dotnet --version 检查。创建并运行一个控制台项目:
dotnet new console -o HelloApp
cd HelloApp
dotnet run
# Hello, World!模板会创建 Program.cs,它使用顶级语句,因此小程序不需要类或 Main 方法:
Console.WriteLine("Hello, World!");变量与基本类型
每个变量都有静态类型。var 让编译器根据值推断类型。值类型(数字、bool、struct)直接保存数据;引用类型(string、类、数组)则指向某个对象。
| 类型 | 示例 | 说明 |
|---|---|---|
int | int n = 42; | 32 位整数 |
long | long big = 10_000_000_000; | 64 位整数 |
double | double x = 3.14; | 64 位浮点数 |
decimal | decimal price = 19.99m; | 十进制,适合表示金额 |
bool | bool ok = true; | true 或 false |
char | char c = 'A'; | UTF-16 代码单元 |
string | string s = "hi"; | 不可变文本 |
var name = "Ada";
int count = 7;
double avg = count / 2.0;
Console.WriteLine($"{name} has {count} items, avg {avg}"); // Ada has 7 items, avg 3.5
Console.WriteLine(count / 2); // 3 (integer division)
Console.WriteLine(int.Parse("12") + 1); // 13
string? nickname = null; // ? marks a nullable reference
Console.WriteLine(nickname ?? "none"); // none$"..." 是插值字符串。新项目默认启用可为空引用类型,因此当可能为 null 的值未经检查就被使用时,编译器会发出警告。
流程控制与方法
int score = 72;
if (score >= 90) Console.WriteLine("A");
else if (score >= 70) Console.WriteLine("B"); // B
else Console.WriteLine("C");
for (int i = 0; i < 3; i++) Console.Write($"{Square(i)} "); // 0 1 4
Console.WriteLine();
foreach (var fruit in new[] { "apple", "pear" }) Console.WriteLine(fruit);
string day = "SAT";
string kind = day switch
{
"SAT" or "SUN" => "weekend",
_ => "weekday",
};
Console.WriteLine(kind); // weekend
Console.WriteLine(Greet("Lin")); // Hello, Lin!
static int Square(int x) => x * x;
static string Greet(string name, string greeting = "Hello") => $"{greeting}, {name}!";switch 表达式和 or 模式属于 C# 的模式匹配。方法可以有参数默认值、命名参数(Greet(name: "Lin"))以及用 => 书写的表达式体。
类、属性与 record
类包含字段、属性(带有 get 和 set 逻辑的字段)和方法。record 是基于值判断相等的类型,非常适合不可变数据。
var acc = new Account("Ann");
acc.Deposit(50);
Console.WriteLine($"{acc.Owner}: {acc.Balance}"); // Ann: 50
var p1 = new Point(3, 4);
var p2 = p1 with { Y = 5 }; // copy with one change
Console.WriteLine(p1); // Point { X = 3, Y = 4 }
Console.WriteLine(p1 == new Point(3, 4)); // True
public class Account
{
public string Owner { get; }
public decimal Balance { get; private set; }
public Account(string owner) => Owner = owner;
public void Deposit(decimal amount)
{
if (amount <= 0) throw new ArgumentException("amount must be positive");
Balance += amount;
}
}
public record Point(int X, int Y);类型声明必须放在同一文件中的顶级语句之后。类支持单继承(class Savings : Account),可以实现任意数量的接口。
集合与 LINQ
System.Collections.Generic 中的泛型集合是日常使用的数据结构。LINQ(Language Integrated Query,语言集成查询)为所有集合增加了 Where、Select、OrderBy 和 GroupBy 等方法。
var nums = new List<int> { 3, 1, 2, 5 };
nums.Add(4);
nums.Sort();
Console.WriteLine(string.Join(", ", nums)); // 1, 2, 3, 4, 5
var ages = new Dictionary<string, int> { ["ann"] = 31, ["bob"] = 25 };
ages["cy"] = 40;
if (ages.TryGetValue("bob", out int bobAge)) Console.WriteLine(bobAge); // 25
var evenSquares = nums.Where(n => n % 2 == 0).Select(n => n * n).ToList();
Console.WriteLine(string.Join(" ", evenSquares)); // 4 16
var oldest = ages.OrderByDescending(kv => kv.Value).First();
Console.WriteLine(oldest.Key); // cy其他常用集合还有:存放不重复元素的 HashSet<T>、Queue<T>、Stack<T>,以及 int[] 这样的定长数组。
标志性特性:async 与 await
C# 首创了 async/await 模型,后来许多语言都采用了它。async 方法返回 Task,并且可以 await 网络请求或文件读取等耗时操作,而不会阻塞线程。
using System.Net.Http;
using var http = new HttpClient();
var sizes = await Task.WhenAll(
GetLengthAsync(http, "https://example.com"),
GetLengthAsync(http, "https://example.org"));
Console.WriteLine($"downloaded {sizes.Sum()} characters");
static async Task<int> GetLengthAsync(HttpClient http, string url)
{
string html = await http.GetStringAsync(url);
return html.Length;
}Task.WhenAll 会同时发起两个请求并等待它们都完成。using var 声明会在作用域结束时释放 HttpClient。
异常
错误以异常表示。先捕获具体的类型,并使用 finally 或 using 做清理。对于经常无效的输入,TryParse 模式可以避免使用异常。
try
{
int age = int.Parse("abc");
}
catch (FormatException ex)
{
Console.WriteLine($"not a number: {ex.Message}");
}
finally
{
Console.WriteLine("done");
}
if (!int.TryParse("41", out int parsed)) parsed = 0;
Console.WriteLine(parsed); // 41一个完整的小程序:词频统计
把控制台项目中的 Program.cs 替换为这段代码,然后运行 dotnet run -- notes.txt。
using System.Text.RegularExpressions;
if (args.Length != 1)
{
Console.Error.WriteLine("usage: dotnet run -- FILE");
return 1;
}
try
{
string text = File.ReadAllText(args[0]).ToLowerInvariant();
var top = Regex.Matches(text, "[a-z']+")
.GroupBy(m => m.Value)
.Select(g => (Word: g.Key, Count: g.Count()))
.OrderByDescending(t => t.Count)
.Take(5);
foreach (var (word, count) in top)
Console.WriteLine($"{count,5} {word}");
return 0;
}
catch (FileNotFoundException)
{
Console.Error.WriteLine($"file not found: {args[0]}");
return 1;
}顶级语句可以读取命令行 args 并返回退出码。新项目通过隐式 using 自动导入 System.IO、System.Linq 和 System.Collections.Generic。
新手常见错误
- 用
double表示金额;应使用decimal来避免二进制舍入误差。 - 忽略可空性警告,它们最终会在运行时变成
NullReferenceException。 - 在对同一个列表的
foreach中修改List<T>,会抛出InvalidOperationException。 - 在长期运行的应用中为每个请求创建新的
HttpClient。请复用同一个实例,或使用IHttpClientFactory。 - 忘记 LINQ 查询是惰性执行的:除非调用
ToList(),否则每次枚举时查询都会重新执行一遍。
接下来学什么
Microsoft Learn 提供官方的 C# 文档,包括语言导览和交互式教程。之后可以学习用于 Web API 的 ASP.NET Core、用于数据库的 Entity Framework Core,或用于游戏的 Unity,并使用 xUnit 或 NUnit 做测试。Visual Studio、安装了 C# Dev Kit 的 VS Code 以及 JetBrains Rider 是常用的编辑器。
常见问题
C# 只能用在 Windows 上吗?
不是。现代 .NET 可运行在 Windows、macOS 和 Linux 上,C# 应用可以部署到 Linux 服务器和容器中。只有 WPF 和 Windows Forms 等部分桌面 UI 框架仅限 Windows。
C# 和 .NET 有什么区别?
C# 是编程语言。.NET 是编译并运行 C# 代码的运行时和库(同样适用于 F# 和 Visual Basic)。
C# 和 Java 相似吗?
在许多方面相似:两者都是静态类型、带垃圾回收、面向对象且采用 C 风格语法的语言。C# 增加了属性、LINQ、async/await、值类型 struct 和 record 等特性。
C# 适合做游戏开发吗?
适合。使用最广泛的游戏引擎之一 Unity 就用 C# 编写游戏脚本,Godot 引擎也支持 C#。