C#中implicit和explicit
理解:
- 使用等号代替构造函数调用的效果
- 以类似重载操作符的形式定义用于类型转换的函数
- 前者类型转换时候直接写等号赋值语法,后者要额外加目标类型的强制转换
- stirng str -> object o -> int a 可以 int a = (int)(str as object)转换通过编译,但没有转换逻辑所以运行会报错,explicit就可以解决这个问题,类似 于dart语言中的 源类型对象.to目标类型() 的意思.
什么是隐式转换?
int i = 1;
double d = i;
什么是显式转换?
double d = 1;
int i = (int)d
implicit
隐式转换,相当于封箱操作如: int i = 1; object obj = i;
如果不理解封箱可以换个例子: int i = 1; double d = i;
double的可取值范围包含了int的全部可取值范围,所以可以int->double隐式转换
explicit
显式转换,相当于拆箱操作如: object obj = 1; int i = (int)obj;
如果不理解封箱可以换个例子: double i = 1; int i = (int) d;
为什么有显式和隐式转换?
在C#本身的类型转换中,
int, uint , float之类的都可以隐式转换到double,是因为 double可以不丢失精度的情况下保存int, uint , float之类类型的值
而 double要想转换回到其他数值类型,则有可能丢失精度,所以我们要强制转换,也就是显式的指定转换的方式,即
double d = 1.1;
//int i = d;//这样不可以转换
int i = (double)d; //这样可以转换,但是会丢精度
此时 i 的值为1而不是1.1(向下取整,即Math.Floor()函数执行后再转为int的相同作用.
故,
方便,是隐式转换的主要目的
明确,精确,安全,是显式转换的主要目的
implicit/explicit的用法
固定以 public static implicit/explicit operator 目标类型(源类型 源类型形参)
的方式使用.
假设我们有人民币Rmb和美元Dollar类
评估资产的时候,默认都用Dollar来作为通用单位,当需要换成Rmb或者其他比重比如Krw的时候,需要显式的,明确的知道要转换的目标币种的类型.
比如隐式转换 Rmb->Dollar
public static implicit operator Dollar(Rmb rmb)
{
//汇率相关的计算
}
再比如显式转换 Dollar->Rmb
public static explicit operator Rmb(Dollar rmb)
{
//汇率先关的计算
}
使用时,隐式转换直接用Rmb可以直接给Dollar赋值
var rmb = new Rmb();
var dollar = rmb;//可以正常编译通过并在运行时正确转换
而
var doaalr = new Dollar();
//var rmb = dollar;//不可以通过编译,因为没有实现从dollar到rmb的隐式转换
var rmb = (Rmb)dollar;//可以通过编译并在运行时正确转换.
设计建议:
不管隐式还是显式转换都要保证类型安全不溢出不抛错
隐式转换设计时尽量源类型和目标类型不要有太多的偏差,否则容易造成歧义,如
var person = new Person(){ Id = 1111 };
int id = person; //这种虽然是方便从person中取出Id属性赋值给id,但理解可能会有偏差.
尽管我们可以用
int personId = person; 仍然是有较大的歧义.读代码的人会想id怎么会是一个"人"对象呢?
所以都不如 var id = person.Id来的直观.
像public class ArgsInfo内定义一个隐式转换从 string [] 到 ArgsInfo就是一个较好的设计
//一段精简的示例代码,实际设计会比这个健壮,仅为了表示该类和 string[] args较好耦合.public class ArgsInfo{private readonly Dictionary<string,string> _args = new();public static implicit operator ArgsInfo(string[] args){var result = new ArgsInfo();foreach (var arg in args){var kv = arg.Split('=');if (kv.Length == 2){result._args[kv[0]] = kv[1];}}return result;}public override string ToString(){var sb = new StringBuilder();foreach (var (key, value) in _args){sb.AppendLine($"{key}={value}");}return sb.ToString();}}public static void Main(string[] args){//就像调用了 var argsInfo = new ArgsInfo(args);ArgsInfo argsInfo = args;Console.WriteLine(argsInfo);}
显示转换设计时, 语义会更明确, 但必要的类型转换说明不可少.丢不丢精度,等都要写清
由于不像函数ConvertXXXToYYY, src.ToDestType<int>(), src.toInt()等直观的通过名称就知道含义且可以传递各种参数如精度之类的,所以保证类型转换的安全稳定和易维护拓展很重要.
完整示例代码带注释:
新建一个cs文件,直接运行Test方法看看效果吧
Rider截图:

/*implicit:隐式转换explicit:显式转换*/using System.Globalization;namespace CS2TS.Test._1_InTestCSFiles;/// <summary>
/// 常量值定义
/// </summary>
public static class Constant
{/// <summary>/// 1美元换多少人民币/// </summary>public const double DollarToRmb = 6.5;/// <summary>/// 1美元换多少韩元/// </summary>public const double DollarToKrw = 1100;
}/// <summary>
/// 人
/// </summary>
public class Person
{/// <summary>/// 名字/// </summary>public string Name { get; set; } = "无名氏";/// <summary>/// 资产,默认以可隐式转换的美元表示,转换成其他货币需要显式转换标明意图/// </summary>public Dollar Money { get; set; } = new();
}public class Rmb
{public double RmbAmount { get; set; }public static implicit operator Dollar(Rmb rmb){return new Dollar{DollarAmount = rmb.RmbAmount / Constant.DollarToRmb};}public static implicit operator Rmb(Dollar dollar){return new Rmb{RmbAmount = dollar.DollarAmount * Constant.DollarToRmb};}public static explicit operator Krw(Rmb rmb){//先把rmb转换成dollar,然后再转换成krwreturn (Dollar)rmb;}public static explicit operator Rmb(Krw krw){//先把krw转换成dollar,然后再转换成rmbreturn (Dollar)krw;}
}/// <summary>
/// 韩元
/// </summary>
public class Krw
{public double KrwAmount { get; set; }/*可以直接用美元换韩元如果换成人民币则需要显式转换*/public static implicit operator Dollar(Krw krw){return new Dollar{DollarAmount = krw.KrwAmount / Constant.DollarToKrw};}public static implicit operator Krw(Dollar dollar){return new Krw{KrwAmount = dollar.DollarAmount * Constant.DollarToKrw};}public static explicit operator Rmb(Krw krw){//先把krw转换成dollar,然后再转换成rmbreturn (Dollar)krw;}public static explicit operator Krw(Rmb rmb){//先把rmb转换成dollar,然后再转换成krwreturn (Dollar)rmb;}
}/// <summary>
/// 美元,作为中间货币,人民币和韩元都可以直接换成美元,但是美元要换成什么,需要显式转换
/// </summary>
public class Dollar
{public double DollarAmount { get; set; }public override string ToString(){return DollarAmount.ToString(CultureInfo.InvariantCulture);}
}public class ImplicitAndExplicit
{public static void Test(){#region 小明,美元换韩元和人民币var ming = new Person{Name = "小明",Money = new Dollar{DollarAmount = 1000}};//他想换成韩元的或者人民币的时候,需要显示的转换var rmbOfMing = (Rmb)ming.Money;Console.WriteLine($"小明有{ming.Money.DollarAmount}美元,换成人民币是{rmbOfMing.RmbAmount}元");var krwOfMing = (Krw)ming.Money;Console.WriteLine($"小明有{ming.Money.DollarAmount}美元,换成韩元是{krwOfMing.KrwAmount}元");#endregion#region 小红,人民币换韩元Console.WriteLine("小红只有人民币1000元,但是出国换货币的时候,都是央行的汇率,所以她的人民币要先转换成美元,然后再转换成其他货币");var rmbOfHong = new Rmb{RmbAmount = 1000};var hong = new Person{Name = "小红",// 不需要显示转换,因为Rmb有implicit转换成DollarMoney = rmbOfHong};//需要显示转换,因为Dollar没有implicit转换成Rmbvar krwOfHong = (Krw)hong.Money;Console.WriteLine($"小红有{hong.Money.DollarAmount}美元,换成韩元是{krwOfHong.KrwAmount}元");#endregion#region 小黑,韩元换人民币Console.WriteLine("小黑只有韩元1000元,但是出国换货币的时候,都是央行的汇率,所以她的韩元要先转换成美元,然后再转换成其他货币");var krwOfHei = new Krw{KrwAmount = 1000};var hei = new Person{Name = "小黑",// 不需要显示转换,因为Krw有implicit转换成DollarMoney = krwOfHei};//需要显示转换,因为Dollar没有implicit转换成Rmbvar rmbOfHei = (Rmb)hei.Money;Console.WriteLine($"小黑有{hei.Money.DollarAmount}美元,换成人民币是{rmbOfHei.RmbAmount}元");#endregion#region 统一用Dollar来表示资产Console.WriteLine($"小明有{ming.Money.DollarAmount}美元");Console.WriteLine($"小红有{hong.Money.DollarAmount}美元");Console.WriteLine($"小黑有{hei.Money.DollarAmount}美元");#endregion#region 统一用Rmb来表示资产Console.WriteLine($"小明有{((Rmb)ming.Money).RmbAmount}人民币");Console.WriteLine($"小红有{((Rmb)hong.Money).RmbAmount}人民币");Console.WriteLine($"小黑有{((Rmb)hei.Money).RmbAmount}人民币");#endregion#region 统一用Krw来表示资产Console.WriteLine($"小明有{((Krw)ming.Money).KrwAmount}韩元");Console.WriteLine($"小红有{((Krw)hong.Money).KrwAmount}韩元");Console.WriteLine($"小黑有{((Krw)hei.Money).KrwAmount}韩元");#endregion}
}
相关文章:
C#中implicit和explicit
理解: 使用等号代替构造函数调用的效果以类似重载操作符的形式定义用于类型转换的函数前者类型转换时候直接写等号赋值语法,后者要额外加目标类型的强制转换stirng str -> object o -> int a 可以 int a (int)(str as object)转换通过编译,但没有转换逻辑所以运行会报错…...
探讨java系统中全局唯一ID实现方案
为什么需要全局唯一ID 我们这里引用美团 Leaf 的场景介绍:在复杂分布式系统中,往往需要对大量的数据和消息进行唯一标识。如在美团点评的金融、支付、餐饮、酒店、猫眼电影等产品的系统中,数据日渐增长,对数据分库分表后需要有一…...
微信小程序(四十四)鉴权组件插槽-登入检测
注释很详细,直接上代码 新增内容: 1.鉴权组件插槽的用法 2.登入检测示范 源码: app.json {"usingComponents": {"auth":"/components/auth/auth"} }app.js App({globalData:{//定义全局变量isLoad:false} })…...
【ES】--ES集成热更新自定义词库(字典)
目录 一、问题描述二、具体实施1、Tomcat实现远程扩展字典2、验证生效3、ES配置远程扩展字典4、为何不重启ES能实现热更新 一、问题描述 问题现象: 前面完成了自定义分词器词库集成到ES中。在实际项目中词库是时刻在变更的,但又不希望重启ES,对此我们应…...
能源管理师——为能源可持续发展护航
能源管理师是在能源管理领域具有专业知识和技能的专业人士,他们的工作对于实现能源的有效利用和可持续发展至关重要。 能源管理师的主要职责是协助企业或组织进行能源管理,包括能源规划、能源审计、节能措施的实施和能源绩效的评估等。他们通过对能源使…...
设计模式理解:单例模式+工厂模式+建设者模式+原型模式
迪米特法则:Law of Demeter, LoD, 最少知识原则LKP 如果两个软件实体无须直接通信,那么就不应当发生直接的相互调用,可以通过第三方转发该调用。其目的是降低类之间的耦合度,提高模块的相对独立性。 所以,在运用迪米特…...
DataX源码分析 writer
系列文章目录 一、DataX详解和架构介绍 二、DataX源码分析 JobContainer 三、DataX源码分析 TaskGroupContainer 四、DataX源码分析 TaskExecutor 五、DataX源码分析 reader 六、DataX源码分析 writer 七、DataX源码分析 Channel 文章目录 系列文章目录前言DataX的Writer写入流…...
为自己的项目媒体资源添加固定高度
为自己的项目媒体资源添加固定高度 未媒体资源添加固定高度,不仅有利于确定懒加载后的切确位置,还可以做骨架屏、loading动画等等,但是因为历史数据中很多没有加高度的媒体资源,所以一直嫌麻烦没有做。 直到这个季度有一个自上而…...
家政小程序系统源码开发:引领智能生活新篇章
随着科技的飞速发展,小程序作为一种便捷的应用形态,已经深入到我们生活的方方面面。尤其在家庭服务领域,家政小程序的出现为人们带来了前所未有的便利。它不仅简化了家政服务的流程,提升了服务质量,还为家政服务行业注…...
多表查询
目录 统计出一张数据表中的数据量 查询 dept 表中的数据量 查询 emp 表中的数据量 实现 emp 与 dept 的多表查询 笛卡尔积 消除笛卡尔积 把数据表 emp 的别名定为 e,数据表 dept 的别名定为 d,然后在查询中分别使用 e 和 d 代替这两个表 Oracle从…...
PHP开发日志 ━━ 深入理解三元操作与一般条件语句的不同
概况 三元运算符的功能与“if…else”流程语句一致。 在一般情况下,三元操作替换if条件语句可以精简代码,并且更为直观,但是在下面的情况中使用三元操作将会返回警告。 借图: 案例 比如原代码: class classA{publ…...
多维时序 | Matlab实现RF-Adaboost随机森林结合Adaboost多变量时间序列预测
多维时序 | Matlab实现RF-Adaboost随机森林结合Adaboost多变量时间序列预测 目录 多维时序 | Matlab实现RF-Adaboost随机森林结合Adaboost多变量时间序列预测预测效果基本介绍程序设计参考资料 预测效果 基本介绍 1.Matlab实现RF-Adaboost随机森林结合Adaboost多变量时间序列预…...
vue3-内置组件-Suspense
Suspense (实验性功能) <Suspense> 是一项实验性功能。它不一定会最终成为稳定功能,并且在稳定之前相关 API 也可能会发生变化。 <Suspense> 是一个内置组件,用来在组件树中协调对异步依赖的处理。它让我们可以在组件树上层等待下层的多个嵌…...
Rust入门:如何在windows + vscode中关闭程序codelldb.exe
在windows中用vscode单步调试rust程序的时候,发现无论是按下stop键,还是运行完程序,调试器codelldb.exe一直霸占着主程序不退出,如果此时对代码进行修改,后续就没法再编译调试了。 目前我也不知道要怎么处理这个事&am…...
git错误整理
remote: Support for password authentication was removed on August 13, 2021. 参考:这篇即可 GnuTLS recv error (-110): The TLS connection was non-properly terminated. 执行下面的指令: git config --global http.sslVerify false...
跟着cherno手搓游戏引擎【22】CameraController、Resize
前置: YOTO.h: #pragma once//用于YOTO APP#include "YOTO/Application.h" #include"YOTO/Layer.h" #include "YOTO/Log.h"#include"YOTO/Core/Timestep.h"#include"YOTO/Input.h" #include"YOTO/KeyCod…...
微信小程序(四十二)wechat-http拦截器
注释很详细,直接上代码 上一篇 新增内容: 1.wechat-http请求的封装 2.wechat-http请求的拦截器的用法演示 源码: utils/http.js import http from "wechat-http"//设置全局默认请求地址 http.baseURL "https://live-api.ith…...
tomcat部署zrlog
1.下载zrlog包,并添加到虚拟机中 1)进入/opt/apache-tomcat-8.5.90/webapps目录 cd /opt/apache-tomcat-8.5.90/webapps2)下载zrlog包 wget http://dl.zrlog.com/release/zrlog-1.7.1-baaecb9-release.war 3)重命名包 mv zrlog-1.7.1-baaecb9-release zrblog 2…...
Ubuntu Desktop 开机数字小键盘
Ubuntu Desktop 开机数字小键盘 1. 开机数字小键盘References 1. 开机数字小键盘 一般情况下,Ubuntu 开机后小键盘区是控制方向键而非数字键,每次开机后若用到数字键都需要按下 NumLock 键。 References [1] Yongqiang Cheng, https://yongqiang.blog…...
树莓派编程基础与硬件控制
1.编程语言 Python 是一种泛用型的编程语言,可以用于大量场景的程序开发中。根据基于谷歌搜 索指数的 PYPL(程序语言流行指数)统计,Python 是 2019 年 2 月全球范围内最为流行 的编程语言 相比传统的 C、Java 等编程语言&#x…...
React 第五十五节 Router 中 useAsyncError的使用详解
前言 useAsyncError 是 React Router v6.4 引入的一个钩子,用于处理异步操作(如数据加载)中的错误。下面我将详细解释其用途并提供代码示例。 一、useAsyncError 用途 处理异步错误:捕获在 loader 或 action 中发生的异步错误替…...
DeepSeek 赋能智慧能源:微电网优化调度的智能革新路径
目录 一、智慧能源微电网优化调度概述1.1 智慧能源微电网概念1.2 优化调度的重要性1.3 目前面临的挑战 二、DeepSeek 技术探秘2.1 DeepSeek 技术原理2.2 DeepSeek 独特优势2.3 DeepSeek 在 AI 领域地位 三、DeepSeek 在微电网优化调度中的应用剖析3.1 数据处理与分析3.2 预测与…...
反向工程与模型迁移:打造未来商品详情API的可持续创新体系
在电商行业蓬勃发展的当下,商品详情API作为连接电商平台与开发者、商家及用户的关键纽带,其重要性日益凸显。传统商品详情API主要聚焦于商品基本信息(如名称、价格、库存等)的获取与展示,已难以满足市场对个性化、智能…...
《用户共鸣指数(E)驱动品牌大模型种草:如何抢占大模型搜索结果情感高地》
在注意力分散、内容高度同质化的时代,情感连接已成为品牌破圈的关键通道。我们在服务大量品牌客户的过程中发现,消费者对内容的“有感”程度,正日益成为影响品牌传播效率与转化率的核心变量。在生成式AI驱动的内容生成与推荐环境中࿰…...
基于Docker Compose部署Java微服务项目
一. 创建根项目 根项目(父项目)主要用于依赖管理 一些需要注意的点: 打包方式需要为 pom<modules>里需要注册子模块不要引入maven的打包插件,否则打包时会出问题 <?xml version"1.0" encoding"UTF-8…...
Python如何给视频添加音频和字幕
在Python中,给视频添加音频和字幕可以使用电影文件处理库MoviePy和字幕处理库Subtitles。下面将详细介绍如何使用这些库来实现视频的音频和字幕添加,包括必要的代码示例和详细解释。 环境准备 在开始之前,需要安装以下Python库:…...
【学习笔记】深入理解Java虚拟机学习笔记——第4章 虚拟机性能监控,故障处理工具
第2章 虚拟机性能监控,故障处理工具 4.1 概述 略 4.2 基础故障处理工具 4.2.1 jps:虚拟机进程状况工具 命令:jps [options] [hostid] 功能:本地虚拟机进程显示进程ID(与ps相同),可同时显示主类&#x…...
RNN避坑指南:从数学推导到LSTM/GRU工业级部署实战流程
本文较长,建议点赞收藏,以免遗失。更多AI大模型应用开发学习视频及资料,尽在聚客AI学院。 本文全面剖析RNN核心原理,深入讲解梯度消失/爆炸问题,并通过LSTM/GRU结构实现解决方案,提供时间序列预测和文本生成…...
2025季度云服务器排行榜
在全球云服务器市场,各厂商的排名和地位并非一成不变,而是由其独特的优势、战略布局和市场适应性共同决定的。以下是根据2025年市场趋势,对主要云服务器厂商在排行榜中占据重要位置的原因和优势进行深度分析: 一、全球“三巨头”…...
【7色560页】职场可视化逻辑图高级数据分析PPT模版
7种色调职场工作汇报PPT,橙蓝、黑红、红蓝、蓝橙灰、浅蓝、浅绿、深蓝七种色调模版 【7色560页】职场可视化逻辑图高级数据分析PPT模版:职场可视化逻辑图分析PPT模版https://pan.quark.cn/s/78aeabbd92d1...
