cv.cm

编码 · 编程语言

C# 入门教程(零基础)

阅读约 9 分钟

简短回答

C# 是微软推出的静态类型、面向对象语言,运行在 .NET 上;.NET 是免费的跨平台运行时,支持 Windows、macOS 和 Linux。安装 .NET SDK,运行 dotnet new console,再 dotnet run 就会输出“Hello, World!”。核心概念包括:类与 record、List<T> 和 Dictionary<K, V> 等泛型集合、LINQ 查询、async/await、模式匹配和异常。

打开JSON 格式化

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、类、数组)则指向某个对象。

类型示例说明
intint n = 42;32 位整数
longlong big = 10_000_000_000;64 位整数
doubledouble x = 3.14;64 位浮点数
decimaldecimal price = 19.99m;十进制,适合表示金额
boolbool ok = true;true 或 false
charchar c = 'A';UTF-16 代码单元
stringstring 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#。

全部编码教程