修飾符是 C# 聲明語義的「調色盤」,精準控制**可見性、繼承、實例化、線程安全、互操作**等核心行為。本文按**作用目標**分類,系統梳理 20+ 修飾符的語法規則、組合限制、典型場景與避坑指南。
一、 訪問修飾符:可見性邊界
| 關鍵字 | 適用目標 | 可見範圍 | 核心口訣 |
public | 類型/成員 | 無限制 | 誰都能用 |
private | 成員 | 聲明類型內部 | 自家專用 |
internal | 類型/成員 | 同一程序集 | 內部公開 |
protected | 成員 | 聲明類型 + 派生類 | 家族共享 |
protected internal | 成員 | 同一程序集 **或** 派生類 | 內部+家族 (聯集) |
private protected | 成員 (C# 7.2+) | 同一程序集 **且** 派生類 | 內部∩家族 (交集) |
默認訪問性:類型 internal,成員 private,介面/枚舉成員 public。
二、 作用於類/結構的修飾符
| 關鍵字 | 語義 | 適用目標 | 組合限制/避坑 |
abstract | 僅作基類,不可實例化,可含抽象成員 | 類/方法/屬性/索引器/事件 | 不可 sealed/static;抽象成員不可 private |
sealed | 禁止繼承 / 禁止再次覆寫 | 類/覆寫方法/屬性 | 方法/屬性必須配合 override;結構體隱式 sealed |
static | 屬於類型而非實例,不可 this | 類/字段/方法/屬性/運算符/事件/構造函數 | 不可用於索引器/構造函數/類型本身 (除嵌套類);靜態構造函數無參、無訪問修飾符 |
partial | 跨文件分部定義,編譯時合併 | 類/結構/介面/方法 | 同一程序集、同一可見性、同一泛型參數;部分方法必須 private、返回 void、不可 out |
三、 僅用於方法/變量的修飾符
| 關鍵字 | 語義 | 關鍵規則 |
const | 編譯期常量,隱式 static | 僅基礎類型/string/enum;聲明時初始化;IL 內聯常值,跨程序集引用需重編譯 |
readonly | 運行期常量,僅聲明處或構造函數賦值 | 可為任意類型;構造函數賦值後不可變;不同實例可不同值 |
new | 隱藏基類同名成員 | 消除編譯警告;不可與 override 共用;破壞多態鏈 |
virtual | 允許派生類覆寫 | 不可 static/abstract/override/private;調用走虛方法表分發 |
override | 覆寫基類虛/抽象成員 | 基類成員必須 virtual/abstract/override;隱式 virtual 可再被覆寫 |
四、 特殊用途修飾符
| 關鍵字 | 語義 | 典型場景/限制 |
event | 聲明事件 (委託受限包裝) | 僅允許 +=/-=;防止外部直接調用/賦值;標準模式 EventHandler<T> |
extern | 外部實現 (非托管/其他程序集別名) | 常配合 [DllImport] + static;不可與 abstract 共用 |
unsafe | 啟用不安全上下文 (指針操作) | 需項目屬性勾選「允許不安全代碼」;僅限信任代碼 |
volatile | 字段可能被 OS/硬件/線程並發修改 | 禁止編譯器/CPU 重排序優化;確保讀取最新值;適用類型:引用/指針/整數/bool/枚舉/IntPtr/泛型引用約束;**不可用於局部變量** |
五、 組合限制速查矩陣
// ✅ 合法
public abstract class Base { protected abstract void M(); }
public sealed class Leaf : Base { protected override void M() {} }
internal static class Utils { public static void Helper() {} }
private protected int FamilyInternalField; // C# 7.2+
readonly struct Point { public int X; public Point(int x) => X = x; }
volatile int _counter; // 字段級
// ❌ 非法
abstract sealed class X {} // 矛盾
private virtual void M() {} // virtual 不可 private
static abstract void M() {} // static 不可 abstract
override void M() {} // 缺少 virtual 基礎
new override void M() {} // 互斥
const int X = GetValue(); // const 需編譯期常量
volatile int LocalVar; // 局部變量不可 volatile
六、 現代 C# 新增修飾符 (C# 7.2+)
readonly struct:整個結構體不可變,in 參數免防禦性複製。
ref struct:僅棧分配 (Span<T>),禁止裝箱/異步/類字段。
in 參數修飾符:只讀傳遞,調用端保證實參不被修改。
ref readonly 返回:避免值類型複製且不可修改。
private protected:程序集內派生類可見 (交集語義)。
修飾符不是裝飾品,而是**靜態契約**。精準選擇 readonly vs const、virtual vs abstract、protected vs private protected,能在編譯期消滅整類運行時 Bug。