修饰符搭配

⚠️ 修饰符搭配注意项

public

公共访问修饰符,表示被 public 修饰的成员 可以在任何地方 被访问

谨慎搭配

private、protected、internal、private protected、protected internal

  • private:被 private 修饰的成员 只能在其声明的类或结构中 被访问
  • protected: 被 protected 修饰的成员 只能在包含它的类和派生类中 被访问的
  • internal:被 internal 修饰的成员 只能在同一程序集中的所有类 被访问
  • private protected:被 private protected 修饰的成员 只能在同一程序集中包含该成员的类或者包含该成员的嵌套类 被访问
  • protected internal:被 protected internal 修饰的成员 只能在同一程序集中的所有类以及派生类 被访问

⚠️:以上 访问修饰符 和 public 修饰符 声明的 访问 范围不一致,不允许 直接搭配 使用 在同一成员

private

私有访问修饰符,被 private 修饰的成员 只能在其声明的类或结构中 被访问

谨慎搭配

internal 、 protected internal

  • internal:被 internal 修饰的成员 只能在同一程序集中的所有类 被访问
  • protected internal:被 protected internal 修饰的成员 只能在同一程序集中的所有类以及派生类 被访问

⚠️:以上 访问修饰符 和 public 修饰符 声明的 访问 范围不一致,不允许 直接搭配 使用 在同一成员

static

静态修饰符, 用于 声明 属于类型本身而不是 特定对象 的静态成员,即 成员属于类而不是实例
静态成员 实现 情况:

  • 静态字段在类加载时被初始化
  • 静态方法被第一次被调用的时候
  • 静态构造函数 在第一次访问 静态成员或创建类的实例时 被 调用

谨慎搭配

abstract、 sealed、 virtual、 override

  • abstract 用于指示抽象成员或抽象类,必须由派生类提供具体的实现
    • 静态修饰符 修饰的 成员 是属于类的,不能交由派生类进行实例化或覆盖
  • sealed 用于指示类或方法不能被继承或重写
    • 静态修饰符 修饰的 成员 是属于类的,使用 sealed 修饰符 来阻止 静态成员 的继承 无意义
  • virtual 用于指示可以在派生类中重写的虚拟成员
    • 静态修饰符 修饰的 成员 是属于类的,使用 virtual 在派生类中 重写 无意义
  • override 重写基类中的虚拟方法
    • 使用 override 重写 的成员是先在基类中已存在,由基类派生重写而来,与静态成员属于类的定义有所违背,故 override 与 static 不能搭配在一起

readonly

readonly 用于表示只读字段,只能在声明或构造函数中赋值

谨慎搭配

sealed、abstract、virtual、override

  • sealed 用于指示类或方法不能被继承或重写
    • readonly 主要用于创建常量或者在构造函数中初始化某个值,确保该值在对象的生命周期内不会被改变,sealed 通常作用于类,readonly 通常作用于类的实例字段,而不是类本身,两者在类的层次上并不适合直接搭配使用
  • abstract 用于指示抽象成员或抽象类,必须由派生类提供具体的实现
    • abstract 要求 派生类 提供 具体的实现 且 抽象成员 在声明时 并 不提供默认值,而 readonly 要求字段在声明时或构造函数中初始化,且值在初始化后不能被修改,故 两者不能直接搭配
  • virtual 用于指示可以在派生类中重写的虚拟成员
    • virtual 允许在派生类中提供新的实现,而 readonly 要求字段的值在初始化后不能被修改,若virtual 要求在派生类中可能提供新的值或实现,则两者有冲突的地方,故不能直接搭配
  • override 重写基类中的虚拟方法
    • override 关键字要求提供一个新的实现,这就涉及到在派生类中可能改变原有实现的情况,readonly 修饰的字段表示只读字段,初始化后不能被修改,两者有冲突的地方,故不能直接搭配

abstract

abstract 用于指示抽象成员或抽象类,必须由派生类提供具体的实现

谨慎搭配

static、sealed、readonly、virtual

  • static 表示静态成员,属于类不属于实例
    • 静态修饰符 修饰的 成员 是属于类的,不能交由派生类进行实例化或覆盖,故两者的搭配不合理
  • sealed 用于指示类或方法不能被继承或重写
    • sealed 禁止 阻止类的派生,而 abstract 却要求类提供派生提供具体的实现,故两者不能直接组合
  • readonly 用于表示只读字段,只能在声明或构造函数中赋值
    • abstract 要求 派生类 提供 具体的实现 且 抽象成员 在声明时 并 不提供默认值,而 readonly 要求字段在声明时或构造函数中初始化,且值在初始化后不能被修改,故 两者不能直接搭配
  • virtual 用于指示虚拟成员,可以在派生类中被重写
    • virtual 成员表示有默认实现的,但可以在派生类中被重写,而 abstract 成员是没有实现的,需要在派生类中提供具体的实现,故 两者有冲突不能直接搭配使用

virtual

virtual 用于指示虚拟成员,可以在派生类中被重写

谨慎搭配

static、sealed、abstract、override

  • static 表示静态成员,属于类不属于实例
    • static 表示成员属于类 而不是 实例,不依赖于实例,virtual 表示成员可以在派生类中被重写,故使用 virtual 在派生类中 重写静态成员 无意义
  • sealed 用于指示类或方法不能被继承或重写
    • sealed 关键字用于禁止方法在进一步的派生类中被重写,而 virtual 则要求 成员 可以在派生类中被重写,它们的组合是不合理的
  • abstract 用于指示抽象成员或抽象类,必须由派生类提供具体的实现
    • virtual 成员表示有默认实现的,但可以在派生类中被重写,而 abstract 成员是没有实现的,需要在派生类中提供具体的实现,故 两者有冲突不能直接搭配使用
  • override 重写基类中的虚拟方法
    • override 要求提供一个新的实现 ,virtual 成员是有默认实现的,但可以在派生类中被重写,两者的功能有某一部分重合,不能直接搭配使用

override

重写基类中的虚拟方法

谨慎搭配

static、sealed、readonly、virtual、new

  • static 表示静态成员,属于类不属于实例
    • 使用 override 重写 的成员是先在基类中已存在,由基类派生重写而来,与静态成员属于类的定义有所违背,故 override 与 static 不能搭配在一起
  • sealed 用于指示类或方法不能被继承或重写
    • sealed 关键字用于禁止方法在进一步的派生类中被重写,而 override 要求方法必须是基类中声明的虚方法,因此它们的组合是不合理的
  • readonly 用于表示只读字段,只能在声明或构造函数中赋值
    • override 关键字要求提供一个新的实现,这就涉及到在派生类中可能改变原有实现的情况,readonly 修饰的字段表示只读字段,初始化后不能被修改,两者有冲突的地方,故不能直接搭配
  • virtual 用于指示虚拟成员,可以在派生类中被重写
    • override 要求提供一个新的实现 ,virtual 成员是有默认实现的,但可以在派生类中被重写,两者的功能有某一部分重合,不能直接搭配使用
  • new 关键字用于隐藏基类成员,但不是通过重写的方式
    • new 关键字用于隐藏基类成员,但不是通过重写的方式,override 则是重写基类中的虚拟方法,override和 new 在语义上相互排斥,因为它们表示对于相同成员的不同行为

sealed

用于指示类或方法不能被继承或重写

谨慎搭配

static、abstract、readonly、override

  • static 表示静态成员,属于类不属于实例
    • sealed 表示该类或方法是终结点,不可再被继承或重写。而 static 表示类型或方法属于类型而不是实例,不依赖于实例。这两者的语义相悖
  • abstract 用于指示抽象成员或抽象类,必须由派生类提供具体的实现
    • sealed 禁止 阻止类的派生,而 abstract 却要求类提供派生提供具体的实现,故两者不能直接组合
  • readonly 用于表示只读字段,只能在声明或构造函数中赋值
    • readonly 主要用于创建常量或者在构造函数中初始化某个值,确保该值在对象的生命周期内不会被改变,sealed 通常作用于类,readonly 通常作用于类的实例字段,而不是类本身,两者在类的层次上并不适合直接搭配使用
  • override 重写基类中的虚拟方法
    • sealed 关键字用于禁止方法在进一步的派生类中被重写,而 override 要求方法必须是基类中声明的虚方法,因此它们的组合是不合理的

static、readonly、const 的区别

可变性:

  • static 是编译时常量,仅有 static 修饰符的 静态成员可以被二次修改
  • readonly 字段是运行时常量,其值只能在声明或构造函数中初始化,之后不可更改
  • const 字段是编译时常量,其值在声明时就被确定,且不能更改

初始化时机:

  • static 字段的值可以在类的静态构造函数中初始化,或者在字段声明时初始化,
  • readonly 字段的值可以在字段声明时或在构造函数中初始化,但一旦初始化后,就不能再修改
  • const 字段必须在声明时初始化,并且只能使用编译时常量,且不能更改

作用域:

  • static 字段是类级别的,所有类的实例共享相同的静态字段
  • readonly 字段是实例级别的,每个类的实例都有自己的只读字段,但所有实例共享相同的值
  • const 字段是类级别的,所有类的实例共享相同的常量值

性能影响:

  • static 字段的值存储在堆上,且在应用程序生命周期内保持不变
  • readonly 字段的值存储在堆上,且在实例生命周期内保持不变
  • const 字段的值在编译时被直接嵌入到使用它的地方,没有额外的字段存储

⚠️: static 和 const 可以创建静态的 字段,但 readonly 不行,readonly 仅代表创建的字段是字段,并不意味在该字段就是静态的

virtual、override

virtual 和 override 是 C# 中用于实现方法重写的关键字

  • virtual 一般用于基类,表示该成员可以在派生类中被重写
  • override 一般用于派生类,表示该类要对基类中的虚方法进行重写

🤔️ 思考

IoC 环境中,为什么常用 readonly 呢?

  1. readonly 修饰的字段 规定 只能在声明时或构造函数内赋值
    • 在声明时的赋值会在 构造函数完成前会被初始化,之后其值不可变
    • 在构造函数赋值 则 允许在创建对象时提供运行时确定的值,并保障这个值是在对象初始化期间设置的唯一机会
  2. IoC 环境中,常用 readonly 来辅助 实现 依赖注入(即在定义一个 只读 属性并由构造函数赋值)
  3. 在依赖注入 时,服务通常会以只读属性的形式注入到类中。使用 readonly 保证这些服务只能在构造函数或对象初始化期间设置,并且在对象的整个生命周期内不会被修改
  4. 使用 readonly 可以防止在对象的其他方法中意外修改这些服务或属性,这样可以确保这些服务在对象创建后保持不变性
  5. 在 C# 中,readonly 字段的初始化是线程安全的一个保障,一旦字段被初始化,它就无可更改,确保数据安全的同时,也有助于防止多线程并发问题的出现
  6. IoC 使用 readonly 实现依赖注入也与 面向对象的 封装 特性 有关
    • 封装本质上就是将对象内部的状态和实现的细节隐藏在 对象之外,并只提供公共接口访问
    • 在IoC中,依赖注入的目标是将组件之间的依赖关系从组件自身解耦,让IoC容器负责管理这些依赖关系。通过使用 readonly 关键字,可以将依赖项注入到对象中,并确保这些依赖项在对象创建后不再被修改。符合了封装的思想,对象内部的状态(即依赖项)受到保护,且只能通过对象的公共接口访问

ps: 本文内容仅来自个人见解,若有错误之处还望斧正

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,188评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,464评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 165,562评论 0 356
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,893评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,917评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,708评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,430评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,342评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,801评论 1 317
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,976评论 3 337
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,115评论 1 351
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,804评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,458评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,008评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,135评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,365评论 3 373
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,055评论 2 355

推荐阅读更多精彩内容