当前位置: 首页 > news >正文

dotnet C# 主构造函数带来的虚属性优势

试试看以下代码,看看 F2 对象被构造出来的时候会发生什么事情,在 D 方法里面是否能够拿到 Foo 属性的值

class Foo
{
}class F1
{public F1(Foo foo){Foo = foo;D();}public virtual Foo Foo { get; }public virtual void D(){}
}class F2 : F1
{public F2(Foo foo) : base(foo){Foo = foo;}public override Foo Foo { get; }public override void D(){var f = Foo;}
}

按照类型的构造函数的顺序,是先执行基类的构造函数,接着再执行子类的构造函数。由此可以知道,只有在子类的构造函数被调用的时候,才会给 Foo 属性赋值。然而 D 方法却在基类的构造函数里面调用,这就意味着此时 F2 里的 D 方法拿到的 Foo 属性必定会是空

以上就是比较经典的在基类调用虚或抽象的方法或属性时会遇到的困难点

主构造函数从语法层面上很好地解决了此问题,将以上的 F2 代码的构造函数变更为主构造函数,如以下代码所示

class F2(Foo foo) : F1(foo)
{public override Foo Foo => foo;public override void D(){var f = Foo;}
}

此时创建 F2 对象时,从 F1 构造函数调用的 F2 的 D 方法拿到的 Foo 属性将不是空。这是因为 Foo 属性是一个没有后备字段的属性,只是从主构造函数捕获的 foo 变量进行返回。由于 foo 是在主构造里面捕获的,属于语法确保类里面可用且有的变量,这就意味着无需等待 F2 执行构造函数即可拿到值

这就意味着主构造函数和显式构造函数之间不是等价变换的,这一点还请大家在做代码变更的时候着重思考是否主构造函数已经是被某个虚或抽象的属性给捕获,且这个属性还可能被基类的构造函数访问到。如果如何以上条件,则主构造函数不能等价修改为显式构造函数写法

也许有伙伴好奇为什么主构造函数能从语法层面上带来这一点的优势,里面的魔法是什么。其实这里面没有什么魔法,只是一个调用顺序的问题,从反编的 IL 可以获得答案。当然了 IL 代码还是比较人类不友好的,我下面贴出来从 IL 转换为低级 C# 代码

   internal class F2 : F1{[CompilerGenerated][DebuggerBrowsable(DebuggerBrowsableState.Never)]private Foo <foo>P; // 这就是主构造函数捕获的变量对应的字段。这是构建的时候生成的。这里的变量名是 `<foo>P` 包含两个尖括号的内容。在 IL 里面尖括号是合法的变量名字符,只是在 C# 里面不被允许。于是充分利用此规则,就可以生成不会在开发者代码被调用的字段public F2(Foo foo){this.<foo>P = foo;base..ctor(this.<foo>P); // 这里的 `.ctor` 就是构造函数的意思。这里的 `base..ctor` 是 `base.` 和 `.ctor` 的意思,即调用 base 基类的 `.ctor` 构造函数}public override Foo Foo{get{return this.<foo>P;}}public override void D(){Foo f = this.Foo;}}

可以看到在主构造函数里面写的 foo 变量,被捕获为 <foo>P 字段。且生成的构造函数的代码调用顺序也十分有趣,先将 foo 赋值给到 <foo>P 字段,再将字段传入到基类的构造函数。于是在这个过程里面,就可以确保 <foo>P 字段一定在基类的构造函数调用之前被赋值。进而让用到主构造函数捕获的变量的代码逻辑可以确保实际构建出来的代码是从一开始赋值的字段获取的,如此就可以解决基类直接或间接访问虚或抽象属性时可能的空问题

必须说明的是,我对主构造函数这个语法是有一些原则的。只有在类足够小的时候,我才会考虑主构造函数。这是因为主构造函数会捕获传入参数变量的缘故,导致在有一定规模的类里面,会和局部变量混淆冲突,影响我的代码阅读。只有在很小的类里面,写主构造函数能够实际地减少代码量的时候,才会考虑使用

本文代码放在 github 和 gitee 上,可以使用如下命令行拉取代码。我整个代码仓库比较庞大,使用以下命令行可以进行部分拉取,拉取速度比较快

先创建一个空文件夹,接着使用命令行 cd 命令进入此空文件夹,在命令行里面输入以下代码,即可获取到本文的代码

git init
git remote add origin https://gitee.com/lindexi/lindexi_gd.git
git pull origin 992ea5dea2fe5711b286ded3454075e223c34146

以上使用的是国内的 gitee 的源,如果 gitee 不能访问,请替换为 github 的源。请在命令行继续输入以下代码,将 gitee 源换成 github 源进行拉取代码。如果依然拉取不到代码,可以发邮件向我要代码

git remote remove origin
git remote add origin https://github.com/lindexi/lindexi_gd.git
git pull origin 992ea5dea2fe5711b286ded3454075e223c34146

获取代码之后,进入 Workbench/WonewheajeaNelbaylairreda 文件夹,即可获取到源代码

更多技术博客,请参阅 博客导航

http://www.rkmt.cn/news/69378.html

相关文章:

  • lazarus使用so遇到的问题
  • 多头潜在注意力优化KV缓存技术详解
  • 2025-12-03 GitHub 热点项目精选
  • 2025年下半年螺丝椒种子品牌综合推荐与选择指南
  • 2025年下半年色素椒种子品牌推荐指南:五家可靠选择解析
  • 2025年下半年加工型辣椒种子品牌推荐Top 5指南:精选榜单与选购技巧
  • 2025年南京笔记本电脑售后维修点推荐:联想华硕戴尔微软惠普宏碁三星哪家服务更优?实测数据与案例验证
  • 2025年长春笔记本电脑售后维修点推荐:联想华硕戴尔微软惠普宏碁三星哪家性价比最高?详细解析与用户评价指南
  • 2025年南京笔记本电脑售后维修点推荐:哪个维修点口碑更好?联想华硕戴尔微软惠普宏碁三星排名指南
  • 2025年温州笔记本电脑售后维修点推荐:联想华硕戴尔微软惠普宏碁三星哪家口碑更好?行业数据与服务比对
  • 2025年北京云恒财网络科技有限责任公司:AI主动营销系统的深度解析与市场价值评估
  • 项目经理学习阶段demo1
  • 全球供应过碳酸钠TOP10名单权威推荐:高含氧量源头工厂直销信息全解
  • 成膜助剂全指南:优质供应商、核心代理商及进口CIF价格一站解析
  • 过碳酸钠厂家权威名单:过碳酸钠出口厂商指南,优质供应商及外贸公司推荐
  • 2025旋转接头厂家实力榜:江苏贝内克以创新密封技术领跑,八大应用场景深度解析
  • XHORSE XSCD01EN Universal Smart Key 5pcs – Perfect for European/American Car Owners Mechanics
  • 2025年天津电缆生产厂家哪家好?天津知名的电缆生产厂家推荐权威名单
  • 2023铝合金桥架厂家实力榜:扬子铝加工以创新技术引领,七大高潜力品牌深度解析
  • 2025一次性手套行业实力榜:沈阳盛道医械以创新技术领跑,八类医用与手术手套深度解析
  • 2025最新耐候胶品牌推荐!建筑密封材料权威榜单发布,性能认证与行业口碑双优推荐
  • 2023应急救援背囊实力榜:迈康时代引领创新,十大品牌核心技术深度解析
  • 2025最新耐候胶品牌推荐!建筑密封材料领军企业权威榜单发布,性能卓越助力工程安全,密封耐候胶生产厂家 / 建筑胶粘剂服务商推荐
  • 2025电线行业实力榜:奔达康电缆以创新技术引领,九大电线类型深度解析
  • 2025最新防霉胶品牌推荐!高端建筑密封胶行业权威榜单发布,资质技术双优助力高湿环境粘结需求
  • 2025最新环保胶品牌推荐!绿色建材领军企业权威榜单发布,技术与环保双优助力行业升级
  • 实验04
  • 2025制氮碳分子筛行业先锋:海华新材引领高效分离技术,六家创新企业深度解析
  • 2025年ISO认证行业技术发展趋势与专业服务解决方案
  • 2025年ISO认证咨询公司前十强权威榜单:上海歆贝领跑行业