← 全部文章 C# 语言

C# 基础:命名空间与访问修饰符

2021 年 3 月 23 日 · 2 分钟读完

目录
  1. 命名空间
  2. 方式一:写全路径
  3. 方式二:using 引入
  4. 重名时会怎样
  5. 小结
  6. 访问修饰符
  7. 不写修饰符时的默认值
  8. 延伸

刚学 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 引入的命名空间里有同名类,编译器会直接报「不明确的引用」。

小结

  1. 命名空间划清模块之间的边界,避免重名;
  2. 可以用全路径,也可以用 using;
  3. 可以多层嵌套,理得清就行;
  4. 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。

# C# # 命名空间 # 访问修饰符

原文首发于 blog.csdn.net