C# 程序结构
本教程共 100 篇 · 第 4 篇 · 更新于 2026-07-31 · 约 9 分钟阅读
4. C# 程序结构
本节目标:看懂一个 C# 文件由哪些部分组成,理解命名空间、using 指令,并分清 Main 方法与顶级语句两种入口写法。
前几章我们用顶级语句”绕开”了程序的外壳。现在回过头把外壳拆开看:命名空间、using、类、Main 方法,各自是什么角色。理解了结构,你读别人的代码才不晕,自己写大一点的程序也知道东西该放哪。
一个”传统写法”的完整程序
先给出带完整结构的版本,方便对照:
namespace CSharpDemo;
class Program
{
static void Main()
{
Console.WriteLine("你好,结构!");
}
}
它和前面 Console.WriteLine(...) 一行版,跑出来效果完全一样。差别只在于:编译器替顶级语句生成的,正是这种带 Main 的结构。
命名空间(namespace)是什么
命名空间(namespace)是给代码”分文件夹”的机制。项目一大,难免有两个都叫 Student 的类——一个管学生信息,一个管奖学金。用命名空间隔开,就能并存且不冲突。
文件范围命名空间(file-scoped namespace)是 C# 10 引入的省事写法:一行 namespace CSharpDemo; 后面不跟花括号,整个文件都属于这个命名空间。这是本教程默认采用的风格。
Note旧写法要用花括号把整个文件包起来:
namespace CSharpDemo { class Program { } }两种等价,但文件范围写法更清爽,也更符合现代 C# 习惯。本教程统一用文件范围写法,只有专门讲命名空间的那一章(第 37 章)才展开对比。
不写命名空间会怎样
你也许想:那我不写 namespace 行不行?行,但代价是”类散落在全局命名空间”。小练习无所谓,项目一大就麻烦:
- 两个同名类撞车时,编译器分不清你要哪个。
- 别人用你的代码时,找不到清晰的归属,引用起来啰嗦。
所以约定是:普通类文件都写上 namespace,把类收进自己的”文件夹”。只有带顶级语句的入口文件例外——它本来就是程序起点,编译器默认把它放进全局命名空间,你不必(也不能)给它套命名空间。
using 指令:引入工具箱
你想用 Console,得先让编译器知道它在哪。Console 实际住在 System 这个命名空间里。传统上要写:
using System;
这就是 using 指令(using directive):告诉编译器”去这个命名空间里找类型”。不写的话,你就得写全名 System.Console.WriteLine(...),很啰嗦。
隐式全局 using(.NET 6+ 模板)
本教程前面所有示例,你都没写过 using System;,照样能用 Console。这是因为 .NET 6 起的默认模板开启了隐式全局 using(implicit global using):编译器自动帮你引入一批最常用命名空间,包括 System、System.Linq、System.Collections.Generic 等。
所以你能直接写 List<string>、Console、int.Parse,都不用手动 using。只有用到冷门命名空间时,才需要自己加一行 using。
Tip想看项目自动引入了哪些命名空间?打开项目里的
obj/Debug/.../项目名.GlobalUsings.g.cs文件,里面列得清清楚楚。初学不必深究,知道”默认就有”即可。
类与方法:真正的执行体
class Program 定义了一个类(class)——C# 是面向对象语言,代码大多装在类里。怎么理解类?把它想成”图纸”:图纸本身不是房子,按图纸能造出很多栋一样的房子。类是图纸,new 出来的对象就是按图纸造出的那栋具体房子。
static void Main() 是入口方法(entry point),程序启动时从这里开始执行。拆开看每个词:
static:属于类本身,不需先new一个对象就能调用。void:这个方法不返回任何值。Main:固定名字,C# 约定它为程序入口。
一个方法(method)就像一台小机器:吃进参数(原料),干完活,吐出返回值(产品)或不吐。Main 是那台”启动整机”的机器。
Main 方法 vs 顶级语句
两种方式本质相同,选哪个看你场景:
| 写法 | 适合 | 特点 |
|---|---|---|
| 顶级语句 | 小程序、脚本、教学示例 | 无 class/Main 外壳,专注逻辑 |
| 传统 Main | 需要清晰组织多个类/方法的大型项目 | 结构明确,便于扩展 |
顶级语句底层就是一段藏在背后的 Main。所以你学顶级语句时,其实已经在使用 Main 了,只是没看见。
Note一个项目里要么用顶级语句,要么自己写
Main,不能两个都要。编译器规定:含顶级语句的文件,不能再有Main方法,也不能套在命名空间花括号里。
using 的另一种用法:静态导入
除了引入命名空间,还能直接导入某个类的静态成员,少写类名:
using static System.Console;
WriteLine("这样可以省掉 Console 前缀");
这种写法在小型示例里很方便,但大项目里为了可读性,通常还是写全 Console.WriteLine。
using 的第三种用法:取别名
当两个不同的命名空间里出现同名类型,或名字太长想简写,可用 using 取别名(alias):
using Project = CSharpDemo.School.Student;
Project p = new(); // 等价于 CSharpDemo.School.Student
别名在”引入第三方库、名字撞车”时特别救命。初学不常见,但知道有这招,将来见到不慌。
一个文件能写多个类吗
能。C# 不要求”一个文件一个类”。你可以在一个 .cs 文件里写多个 class,只要它们不在同一个命名空间里撞名即可。不过约定俗成的做法是”一个文件放一个类”,且文件名和类名一致,方便查找。本教程为聚焦单点,示例常把相关类放一起,你实际项目里按”一文件一类”组织更清晰。
顶级语句能和命名空间共存吗
不能。含顶级语句的文件,编译器会把它当成”程序入口”,不允许再写命名空间声明或 Main 方法。所以:
- 写顶级语句的入口文件:直接用顶层语句,不写
namespace。 - 写类库/普通类文件:用
namespace CSharpDemo;组织。
本教程的入口示例走顶级语句,讲结构时再补命名空间外壳,两者不冲突,只是出现在不同文件里。
Tip记住一句话:入口文件负责”跑”(顶级语句),其他文件负责”定义”(类、命名空间)。职责分开,项目越大越不乱。
一个带方法的类示例
把前面说的”类+方法”落在代码上,感受结构怎么搭:
namespace CSharpDemo;
class Calculator
{
public int Add(int a, int b)
{
return a + b;
}
}
// 在另一个文件或同文件的方法之外,可这样调用:
// var calc = new Calculator();
// int result = calc.Add(2, 3);
Calculator 是类,Add 是它对外提供的方法:接收两个整数参数,返回它们的和。public 表示”谁都能用”。这个骨架你以后会写无数遍。
常见疑问解答
问:不写 namespace 会出错吗?
顶级语句的入口文件可以不写,编译器默认放进全局命名空间。但普通类文件建议写 namespace,否则类会散落在全局,大项目易冲突。
问:using 写错位置会怎样?
using 指令必须放在文件顶部(任何语句之前)。顶级语句文件里,把 using 写在代码最前面即可。放错位置编译器会直接报错,按提示挪到顶就行。
问:类和方法必须 public 吗?
入门示例为了简单常省略修饰符。实际项目里,对外暴露的用 public,内部用的用 private。可见性(第 29 章)是面向对象的护栏,初学先不纠结。
问:方法里能再写方法吗?
能,那叫”局部函数”(第 52 章会讲)。现在你只要知道:常规做法是把方法写在类里,而不是直接塞进 Main。
要点速记
- 文件范围命名空间
namespace X;是 C# 10 的省事写法。 - 隐式全局 using 免写常见
using指令;using static省类名,using 别名解决重名。 - 类像图纸、对象像按图造出的实物;方法吃参数、干活的机器。
- 类承载逻辑,
Main或顶级语句是程序入口。 - 顶级语句与
namespace/Main不能同文件出现。
小结与下一步
现在你能看懂一段 C# 的骨架了:文件范围命名空间组织归属,隐式全局 using 让你免写常见引用,类与方法承载真正逻辑,而 Main 或顶级语句是起点。这些结构像房子的框架,接下来我们要往里填”内容”——从注释和命名规范开始。
下一章讲注释与代码约定,好代码首先要让别人(包括未来的你)看得懂。