技术速递|使用主构造函数重构 C# 代码

作者:David Pine
排版:Alan Wang

作为 .NET 8 一部分的 C# 12 引入了一组引人注目的新功能!在这篇文章中,我们将探讨其中一个功能,特别是主构造函数,解释其用法和相关性。然后,我们将演示一个重构示例,以展示如何将其应用到您的代码中,并讨论其好处和潜在的缺陷。这将帮助您了解这一更改的影响并有助于您决定是否采用该功能。

主构造函数

主构造函数被认为是一项“C#日常”的开发人员功能。它们允许您在一个简洁的声明中定义类或结构及其构造函数。这可以帮助您减少需要编写的样板代码量。如果您一直在关注 C# 版本,您可能熟悉记录类型,其中包括主构造函数的第一个示例。

与记录类型的区别

记录类型作为类或结构的类型修饰符引入,这简化了构建简单类(如数据容器)的语法。记录可以包括主构造函数。该构造函数不仅生成一个支持字段,而且还为每个参数公开一个公共属性。与传统的类或结构类型不同,在传统的类或结构类型中,主构造函数参数可以在整个类定义中访问,而记录被设计为透明的数据容器。他们本质上支持基于值的相等,这与他们作为数据持有者的预期角色相一致。因此,它们的主构造函数参数可以作为属性访问是合乎逻辑的。

重构示例

.NET 提供了许多模板,如果您曾经创建过 Worker Service,您可能见过以下 Worker 类模板代码:

namespace Example.Worker.Service
{public class Worker : BackgroundService{private readonly ILogger<Worker> _logger;public Worker(ILogger<Worker> logger){_logger = logger;}protected override async Task ExecuteAsync(CancellationToken stoppingToken){while (!stoppingToken.IsCancellationRequested){if (_logger.IsEnabled(LogLevel.Information)){_logger.LogInformation("Worker running at: {time}", DateTimeOffset.Now);}await Task.Delay(1000, stoppingToken);}}}
}

前面的代码是一个简单的 Worker 服务,每秒记录一条消息。目前,Worker 类有一个构造函数,它将 ILogger实例作为参数,并将其分配给相同类型的只读字段。此类型信息位于两个位置,即构造函数的定义中,以及字段本身。这是 C# 代码中的常见模式,但可以使用主构造函数进行简化。

值得一提的是,Visual Studio Code 中不提供此特定功能的重构工具,但您可以手动重构主构造函数。若要在 Visual Studio 中使用主构造函数重构此代码,可以使用“使用主构造函数(并删除字段)”重构选项。右键单击 Worker 构造函数,选择“快速操作和重构…”(或按 Ctrl + .),然后选择“使用主构造函数”(并删除字段)。

请查看以下视频,演示使用主构造函数重构功能:

refactor-primary-ctor

现在生成的代码类似于以下 C# 代码:

namespace Example.Worker.Service
{public class Worker(ILogger<Worker> logger) : BackgroundService{protected override async Task ExecuteAsync(CancellationToken stoppingToken){while (!stoppingToken.IsCancellationRequested){if (logger.IsEnabled(LogLevel.Information)){logger.LogInformation("Worker running at: {time}", DateTimeOffset.Now);}await Task.Delay(1000, stoppingToken);}}}
}

就这样,您已经成功重构了 Worker 类以使用主构造函数!ILogger 字段已被删除,并且构造函数已替换为主构造函数。这使得代码更加简洁,更容易阅读。记录器实例现在在整个类中可用(因为它在范围内),而不需要单独的字段声明。

其他注意事项

主构造函数可以删除在构造函数中分配的手写字段声明,但需要注意。如果您将字段定义为只读,那么它们在功能上并不完全等效,因为非记录类型的主构造函数参数是可变的。因此,当您使用这种重构方法时,请注意您正在更改代码的语义。如果要保持只读行为,请就地使用字段声明并使用主构造函数参数分配该字段:

namespace Example.Worker.Service;
public class Worker(ILogger<Worker> logger) : BackgroundService
{private readonly ILogger<Worker> _logger = logger;protected override async Task ExecuteAsync(CancellationToken stoppingToken){while (!stoppingToken.IsCancellationRequested){if (_logger.IsEnabled(LogLevel.Information)){_logger.LogInformation("Worker running at: {time}", DateTimeOffset.Now);}await Task.Delay(1000, stoppingToken);}}
}

其他构造函数

当您定义主构造函数时,您仍然可以定义其他构造函数。然而,这些构造函数必须调用主构造函数。调用主构造函数可确保在类声明中的所有位置进行初始化主构造函数参数。如果需要定义其他构造函数,则必须使用 this 关键字调用主构造函数。

namespace Example.Worker.Service
{// Primary constructorpublic class Worker(ILogger<Worker> logger) : BackgroundService{private readonly int _delayDuration = 1_000;// Secondary constructor, calling the primary constructorpublic Worker(ILogger<Worker> logger, int delayDuration) : this(logger){_delayDuration = delayDuration;}// Omitted for brevity...}
}

并不总是需要额外的构造函数。让我们进行一些额外的重构以包含一些其他功能!

额外重构

主构造函数非常棒,但是我们还可以做更多事情来改进代码。

C# 包含文件范围的命名空间。它们是减少嵌套级别和提高可读性的重要功能。继续前面的示例,将光标放在命名空间名称的末尾,然后按 ; 键(Visual Studio Code 不支持此操作,但您可以手动执行此操作)。这会将命名空间转换为文件范围的命名空间。

请查看以下演示此功能的视频:

refactor-file-scope-ns

经过一些额外的编辑,最终的重构代码如下:

namespace Example.Worker.Service;
public sealed class Worker(ILogger<Worker> logger) : BackgroundService
{protected override async Task ExecuteAsync(CancellationToken stoppingToken){while (!stoppingToken.IsCancellationRequested){if (logger.IsEnabled(LogLevel.Information)){logger.LogInformation("Worker running at: {time}", DateTimeOffset.Now);}await Task.Delay(1_000, stoppingToken);}}
}

除了重构文件范围的命名空间之外,我还添加了 seal 修饰符,因为在多种情况下都有性能上的优势。最后,我还使用数字分隔符功能更新了传递到 Task.Delay 的数字文字,以提高可读性。 您知道还有很多方法可以简化您的代码吗? 查看 C# 中的新增功能以了解更多信息!

后续步骤

在您自己的代码中尝试一下!寻找机会使用主构造函数重构代码,并了解它如何简化您的代码库。 如果您使用的是 Visual Studio,请查看重构工具。 如果您使用的是 Visual Studio Code,您可以手动重构。若要了解更多信息,请浏览以下资源:

  • C# 12 中的主构造函数
  • Visual Studio:其他快速操作
  • Visual Studio Code:C# 快速操作和重构

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/19509.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

华为OD刷题C卷 - 每日刷题 1

1、&#xff08;两数之和&#xff09;&#xff1a; 这段代码是针对力扣&#xff08;LeetCode&#xff09;上的“两数之和”问题。它提供了一个Java类Solution&#xff0c;其中包含一个方法twoSum&#xff0c;该方法接收一个整数数组nums和一个整数目标值target。目的是找出数组…

Idea的相关操作

1、关闭自动更新 点击左上角File->Setting&#xff0c;进入配置页面&#xff0c;点击Appearance & Behavior > System Settings > Updates&#xff0c;取消勾选更新选项&#xff0c;如图&#xff1b; 2、代码提示忽略大小写 点击左上角File->Setting&#xf…

用Unityhub安装unity2018.3.0和vuforia

打开下载网址 https://unity.cn/releases/full/2018 选择2018.3.x 找到2018.3.0后&#xff0c;点击从UnityHub下载 然后unityhub会弹出安装界面 只勾选这两个&#xff0c;其余的全部取消勾选&#xff0c;默认勾选上的也取消掉&#xff0c;然后点击安装

【数据分享】2009-2022年我国省份级别的轨道交通相关指标(20多项指标)

《中国城市建设统计年鉴》中细致地统计了我国城市市政公用设施建设与发展情况&#xff0c;在之前的文章中&#xff0c;我们分享过基于2006-2022年《中国城市建设统计年鉴》整理的2006—2022年我国省份级别的市政设施水平相关指标、2006-2022年我国省份级别的各类建设用地面积数…

String 类

目录&#xff1a; 一. 认识 String 类 二. String 类的基本用法 三. String对象的比较 四.字符串的不可变性 五. 认识 StringBuffer 和 StringBuilder 一. 认识 String 类&#xff1a; 在C语言中已经涉及到字符串了&#xff0c;但是在C语言中要表示字符串只能使用字符数组或者…

Unity2D横版摄像机跟随

在Unity2D横版游戏中&#xff0c;摄像机跟随是一个非常重要的功能。一个流畅的摄像机跟随系统可以让玩家更好地沉浸在游戏世界中。本文将介绍如何在Unity中实现2D横版摄像机跟随&#xff0c;并分享一些优化技巧。 一、准备工作 在开始实现摄像机跟随之前&#xff0c;请确保您…

论文写作学习(持续更新中...)

我总感觉论文写作是有模板的&#xff0c;这篇博客就希望能够把平时的收获做积累&#xff0c;慢慢从中提炼出模板(希望能早点儿学到吧~)。因为内容可能会有点儿散&#xff0c;所以这篇博客决定还是以模块的方式去写&#xff0c;慢慢的如果逻辑能组合会进行模块的合并。   ps&a…

MFC 模态对话框的实现原理

参考自MFC 模态对话框的实现原理 - 西昆仑 - OSCHINA - 中文开源技术交流社区 1. 模态对话框 在涉及 GUI 程序开发的过程中&#xff0c;常常有模态对话框以及非模态对话框的概念 模态对话框&#xff1a;在模态对话框活动期间&#xff0c;父窗口是无法进行消息响应&#xff0…

JavaEE初阶多线程 (5)

1.锁的策略 1.1锁的策略是什么 这个锁的策略可以理解为&#xff0c;一种做法&#xff0c;相当于当你遇到锁竞争&#xff0c;加锁解锁&#xff0c;的情况你会怎么做。 乐观锁可以理解为疫情的时候比较乐观就买了最基本的物资&#xff0c; 买的时候非常方便 1.2乐观锁 当效率…

Wireshark抓包后的报文太大,如何拆分?

背景&#xff1a;抓包获取到一个400多兆的网络数据包.pcapng文件&#xff0c;使用wireshark软件可以正常打开。但需要把文件导出为.json文件&#xff0c;从而方便对报文内容做过滤分析。使用wireshark自带的导出功能导出后发现生成的.json文件大小为2G多&#xff0c;使用notepa…

Python实现定时任务的方式

大家好&#xff0c;在当今数字化的时代&#xff0c;定时任务的需求在各种应用场景中频繁出现。无论是数据的定时更新、周期性的任务执行&#xff0c;还是特定时间点的操作触发&#xff0c;Python 都为我们提供了强大而灵活的手段来实现这些定时任务。当我们深入探索 Python 的世…

【机器学习】AI大模型的探索—浅谈ChatGPT及其工作原理

&#x1f4dd;个人主页&#xff1a;哈__ 期待您的关注 目录 &#x1f4da;介绍ChatGPT 1.1 什么是ChatGPT 1.2 ChatGPT的应用场景 &#x1f4a1;基础概念 1. 人工智能和机器学习 1.1 人工智能&#xff08;AI&#xff09;简介 1.2 机器学习&#xff08;ML&#xff09;简…

【面结构光三维重建】0.基于openCV实现相机的标定

1.标定结果 2.相机标定原理 相机标定是计算机视觉和机器视觉领域中的重要技术,用于确定相机成像的几何关系和畸变特性,以提高成像的精度和稳定性。该技术广泛应用于三维重建、机器人视觉、自动驾驶等领域。 世界坐标系:由用户定义的三维世界坐标系,描述物体和相机在真实世…

第二十五章新增H5基础(以及视频~兼容)

1.HTML5中新增布局标签 HTML5新增了页眉&#xff0c;页脚&#xff0c;内容块等文档结构相关标签&#xff0c;可以使文档结构更加清晰明了。 1.新增的结构标签 1、<header>标签 定义文档或者文档中内容块的页眉。通常可以包含整个页面或一个内容区域的标题&#xff0c…

GEYA格亚GRT8-M多种功能时间继电器交流AC220V DC24V延时断开小巧

品牌 GEYA 型号 GRT8-M1 AC/DC12-240 产地 中国大陆 颜色分类 GRT8-M1 A220,GRT8-M1 AC/DC12-240,GRT8-M2 A220,GRT8-M2 AC/DC12-240 GRT8-M&#xff0c;多功能型&#xff0c;时间继电器&#xff1a;LED指示灯&#xff0c;触头容量大&#xff0c;电压超宽&#xff0c;阻…

文件流转MultipartFile,不使用MockMultipartFile的方式

MockMultipartFile 是一个用于测试的模拟类&#xff0c;通常在单元测试或集成测试中模拟 MultipartFile 的行为。它属于 Spring 框架的测试包 org.springframework.mock.web 中的一部分&#xff0c;不应该在生产环境中使用。 因此我们采用实现MultipartFile接口类的方式&#…

2024.5.29晚训参考代码

因为本套题没有BFS例题&#xff0c;所以我先把BFS模板放着 #include<bits/stdc.h> using namespace std; int n,m;//n*m的棋盘 int dis[402][402]; bool vis[402][402]; int X[]{-2,-2,-1,-1,1,1,2,2};//偏移量的表 int Y[]{-1,1,-2,2,-2,2,-1,1};//定义一个数组&…

PDF盖骑缝章

在PDF文件上加盖骑缝章&#xff0c;您可以采取以下几种方法之一&#xff1a; 使用Adobe Acrobat&#xff1a; 打开Adobe Acrobat软件&#xff0c;加载PDF文件。在工具栏选择“工具”选项&#xff0c;找到“骑缝章”或“印章”工具。选择或上传您的骑缝章图片&#xff0c;将其放…

Dify数据库结构导出到PowerDesigner

即刻关注&#xff0c;获取更多 关注公众号 N学无止界 获取更多 Dify数据库结构导出到PowerDesigner Dify简介 Dify简介 欢迎使用 Dify Dify 是一款开源的大语言模型(LLM) 应用开发平台。它融合了后端即服务&#xff08;Backend as Service&#xff09;和 LLMOps 的理念&…

FFmpeg开发笔记(三十一)使用RTMP Streamer开启APP直播推流

RTMP Streamer是一个安卓手机端的开源RTMP直播推流框架&#xff0c;可用于RTMP直播和RTSP直播&#xff0c;其升级版还支持SRT直播&#xff08;腾讯视频云就采用SRT协议&#xff09;。RTMP Streamer支持的视频编码包括H264、H265、AV1等等&#xff0c;支持的音频编码包括AAC、G7…