C# 基础:命名空间与访问修饰符
2021 年 3 月 23 日 · 2 分钟读完
刚学 C# 时的两篇笔记,合在一起。
命名空间
C# 程序靠命名空间组织。可以把命名空间当成文件夹,类当成文件:要找到一个文件,就从顶层文件夹一层层往下找;不同文件夹里可以有同名文件,不同命名空间里也可以有同名的类。
先准备一个类库,命名空间里还可以嵌套命名空间:
namespace Class1
{
class One
{
public int GetOne() => 1;
}
namespace Class2 // 嵌套命名空间,完整路径是 Class1.Class2
{
class One
{
public int GetOne() => 2;
}
}
}
方式一:写全路径
var a = new Class1.One();
Console.Write(a.GetOne()); // 1
var b = new Class1.Class2.One();
Console.Write(b.GetOne()); // 2
方式二:using 引入
using 相当于把那个命名空间里的类型放进当前作用域,之后直接写类名:
using Class1.Class2;
var one = new One();
Console.Write(one.GetOne()); // 2
重名时会怎样
如果当前命名空间里也有一个 One,编译器优先用自己的,using 进来的同名类会被挡住,于是报「找不到 GetOne 方法」。这时退回方式一,写全路径就行:
using Class1;
namespace console
{
class One { } // 和 Class1.One 重名
class Program
{
static void Main(string[] args)
{
// var x = new One(); // 用的是 console.One,没有 GetOne,报错
var x = new Class1.One(); // 写全路径
Console.Write(x.GetOne());
}
}
}
如果两个 using 引入的命名空间里有同名类,编译器会直接报「不明确的引用」。
小结
- 命名空间划清模块之间的边界,避免重名;
- 可以用全路径,也可以用
using; - 可以多层嵌套,理得清就行;
using引入后可能和本地类重名,重名时写全路径。
访问修饰符
| 修饰符 | 能访问的范围 |
|---|---|
public |
任何地方 |
private |
只有当前类,子类和实例都不行 |
protected |
当前类和子类,实例不行 |
internal |
当前程序集(同一个 dll 或 exe) |
protected internal |
protected 或 internal,满足一个就行 |
private protected |
protected 且 internal:同一程序集里的子类(C# 7.2 起) |
class AccessModifier
{
public int a = 1;
private int b = 2;
protected int c = 3;
internal int d = 4;
protected internal int e = 5;
}
class SubClass : AccessModifier
{
public int GetB() => b; // 报错:private 子类也看不到
public int GetC() => c; // 可以:protected 子类能访问
}
var x = new SubClass();
Console.Write(x.a); // 1
Console.Write(x.b); // 报错
Console.Write(x.c); // 报错:protected 不能通过实例访问
Console.Write(x.GetC()); // 3
Console.Write(x.d); // 4,同一程序集
Console.Write(x.e); // 5
internal 的效果要换个项目才看得出来。在同一个解决方案里新建一个项目,引用上面的程序集,就只剩 public 的 a 能访问:

不写修饰符时的默认值
| 位置 | 默认 | 可以用 |
|---|---|---|
| 命名空间下的类、结构体、接口、枚举 | internal |
public、internal |
| 类的字段、属性、方法 | private |
全部六种 |
| 结构体的成员 | private |
不能用带 protected 的,因为结构体不能被继承 |
| 接口成员 | public |
C# 8 起也可以写别的,用于默认实现 |
| 枚举成员 | public |
不能写修饰符 |
类没写构造函数时,编译器生成的默认构造函数是 public 的(抽象类是 protected)。
延伸
- 文件范围命名空间(C# 10):文件开头写
namespace MyApp.Services;,整个文件都属于它,少一层缩进。新项目基本都这么写。 - 全局 using(C# 10):
global using System.Text;写一次,整个项目都生效。.NET 6 起的新项目还会开启ImplicitUsings,自动引入System、System.Linq等常用命名空间。 - using 别名:
using Hw = HalconDotNet.HWindow;可以给长名字或者重名的类起个别名,解决上面的重名问题更优雅。 file修饰符(C# 11):类型只在当前文件可见,适合源生成器或者文件内部的小工具类。- 想让测试项目访问 internal:在被测项目里加
[assembly: InternalsVisibleTo("MyApp.Tests")],不用为了测试把东西改成 public。
原文首发于 blog.csdn.net