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

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 的场景介绍&#xff1a;在复杂分布式系统中&#xff0c;往往需要对大量的数据和消息进行唯一标识。如在美团点评的金融、支付、餐饮、酒店、猫眼电影等产品的系统中&#xff0c;数据日渐增长&#xff0c;对数据分库分表后需要有一…...

微信小程序(四十四)鉴权组件插槽-登入检测

注释很详细&#xff0c;直接上代码 新增内容&#xff1a; 1.鉴权组件插槽的用法 2.登入检测示范 源码&#xff1a; app.json {"usingComponents": {"auth":"/components/auth/auth"} }app.js App({globalData:{//定义全局变量isLoad:false} })…...

【ES】--ES集成热更新自定义词库(字典)

目录 一、问题描述二、具体实施1、Tomcat实现远程扩展字典2、验证生效3、ES配置远程扩展字典4、为何不重启ES能实现热更新 一、问题描述 问题现象: 前面完成了自定义分词器词库集成到ES中。在实际项目中词库是时刻在变更的&#xff0c;但又不希望重启ES&#xff0c;对此我们应…...

能源管理师——为能源可持续发展护航

能源管理师是在能源管理领域具有专业知识和技能的专业人士&#xff0c;他们的工作对于实现能源的有效利用和可持续发展至关重要。 能源管理师的主要职责是协助企业或组织进行能源管理&#xff0c;包括能源规划、能源审计、节能措施的实施和能源绩效的评估等。他们通过对能源使…...

设计模式理解:单例模式+工厂模式+建设者模式+原型模式

迪米特法则&#xff1a;Law of Demeter, LoD, 最少知识原则LKP 如果两个软件实体无须直接通信&#xff0c;那么就不应当发生直接的相互调用&#xff0c;可以通过第三方转发该调用。其目的是降低类之间的耦合度&#xff0c;提高模块的相对独立性。 所以&#xff0c;在运用迪米特…...

DataX源码分析 writer

系列文章目录 一、DataX详解和架构介绍 二、DataX源码分析 JobContainer 三、DataX源码分析 TaskGroupContainer 四、DataX源码分析 TaskExecutor 五、DataX源码分析 reader 六、DataX源码分析 writer 七、DataX源码分析 Channel 文章目录 系列文章目录前言DataX的Writer写入流…...

为自己的项目媒体资源添加固定高度

为自己的项目媒体资源添加固定高度 未媒体资源添加固定高度&#xff0c;不仅有利于确定懒加载后的切确位置&#xff0c;还可以做骨架屏、loading动画等等&#xff0c;但是因为历史数据中很多没有加高度的媒体资源&#xff0c;所以一直嫌麻烦没有做。 直到这个季度有一个自上而…...

家政小程序系统源码开发:引领智能生活新篇章

随着科技的飞速发展&#xff0c;小程序作为一种便捷的应用形态&#xff0c;已经深入到我们生活的方方面面。尤其在家庭服务领域&#xff0c;家政小程序的出现为人们带来了前所未有的便利。它不仅简化了家政服务的流程&#xff0c;提升了服务质量&#xff0c;还为家政服务行业注…...

多表查询

目录 统计出一张数据表中的数据量 查询 dept 表中的数据量 查询 emp 表中的数据量 实现 emp 与 dept 的多表查询 笛卡尔积 消除笛卡尔积 把数据表 emp 的别名定为 e&#xff0c;数据表 dept 的别名定为 d&#xff0c;然后在查询中分别使用 e 和 d 代替这两个表 Oracle从…...

PHP开发日志 ━━ 深入理解三元操作与一般条件语句的不同

概况 三元运算符的功能与“if…else”流程语句一致。 在一般情况下&#xff0c;三元操作替换if条件语句可以精简代码&#xff0c;并且更为直观&#xff0c;但是在下面的情况中使用三元操作将会返回警告。 借图&#xff1a; 案例 比如原代码&#xff1a; class classA{publ…...

多维时序 | Matlab实现RF-Adaboost随机森林结合Adaboost多变量时间序列预测

多维时序 | Matlab实现RF-Adaboost随机森林结合Adaboost多变量时间序列预测 目录 多维时序 | Matlab实现RF-Adaboost随机森林结合Adaboost多变量时间序列预测预测效果基本介绍程序设计参考资料 预测效果 基本介绍 1.Matlab实现RF-Adaboost随机森林结合Adaboost多变量时间序列预…...

vue3-内置组件-Suspense

Suspense (实验性功能) <Suspense> 是一项实验性功能。它不一定会最终成为稳定功能&#xff0c;并且在稳定之前相关 API 也可能会发生变化。 <Suspense> 是一个内置组件&#xff0c;用来在组件树中协调对异步依赖的处理。它让我们可以在组件树上层等待下层的多个嵌…...

Rust入门:如何在windows + vscode中关闭程序codelldb.exe

在windows中用vscode单步调试rust程序的时候&#xff0c;发现无论是按下stop键&#xff0c;还是运行完程序&#xff0c;调试器codelldb.exe一直霸占着主程序不退出&#xff0c;如果此时对代码进行修改&#xff0c;后续就没法再编译调试了。 目前我也不知道要怎么处理这个事&am…...

git错误整理

remote: Support for password authentication was removed on August 13, 2021. 参考&#xff1a;这篇即可 GnuTLS recv error (-110): The TLS connection was non-properly terminated. 执行下面的指令&#xff1a; git config --global http.sslVerify false...

跟着cherno手搓游戏引擎【22】CameraController、Resize

前置&#xff1a; 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拦截器

注释很详细&#xff0c;直接上代码 上一篇 新增内容&#xff1a; 1.wechat-http请求的封装 2.wechat-http请求的拦截器的用法演示 源码&#xff1a; utils/http.js import http from "wechat-http"//设置全局默认请求地址 http.baseURL "https://live-api.ith…...

tomcat部署zrlog

1.下载zrlog包&#xff0c;并添加到虚拟机中 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. 开机数字小键盘 一般情况下&#xff0c;Ubuntu 开机后小键盘区是控制方向键而非数字键&#xff0c;每次开机后若用到数字键都需要按下 NumLock 键。 References [1] Yongqiang Cheng, https://yongqiang.blog…...

树莓派编程基础与硬件控制

1.编程语言 Python 是一种泛用型的编程语言&#xff0c;可以用于大量场景的程序开发中。根据基于谷歌搜 索指数的 PYPL&#xff08;程序语言流行指数&#xff09;统计&#xff0c;Python 是 2019 年 2 月全球范围内最为流行 的编程语言 相比传统的 C、Java 等编程语言&#x…...

【CSS position 属性】static、relative、fixed、absolute 、sticky详细介绍,多层嵌套定位示例

文章目录 ★ position 的五种类型及基本用法 ★ 一、position 属性概述 二、position 的五种类型详解(初学者版) 1. static(默认值) 2. relative(相对定位) 3. absolute(绝对定位) 4. fixed(固定定位) 5. sticky(粘性定位) 三、定位元素的层级关系(z-i…...

【SQL学习笔记1】增删改查+多表连接全解析(内附SQL免费在线练习工具)

可以使用Sqliteviz这个网站免费编写sql语句&#xff0c;它能够让用户直接在浏览器内练习SQL的语法&#xff0c;不需要安装任何软件。 链接如下&#xff1a; sqliteviz 注意&#xff1a; 在转写SQL语法时&#xff0c;关键字之间有一个特定的顺序&#xff0c;这个顺序会影响到…...

EtherNet/IP转DeviceNet协议网关详解

一&#xff0c;设备主要功能 疆鸿智能JH-DVN-EIP本产品是自主研发的一款EtherNet/IP从站功能的通讯网关。该产品主要功能是连接DeviceNet总线和EtherNet/IP网络&#xff0c;本网关连接到EtherNet/IP总线中做为从站使用&#xff0c;连接到DeviceNet总线中做为从站使用。 在自动…...

(转)什么是DockerCompose?它有什么作用?

一、什么是DockerCompose? DockerCompose可以基于Compose文件帮我们快速的部署分布式应用&#xff0c;而无需手动一个个创建和运行容器。 Compose文件是一个文本文件&#xff0c;通过指令定义集群中的每个容器如何运行。 DockerCompose就是把DockerFile转换成指令去运行。 …...

Spring AI与Spring Modulith核心技术解析

Spring AI核心架构解析 Spring AI&#xff08;https://spring.io/projects/spring-ai&#xff09;作为Spring生态中的AI集成框架&#xff0c;其核心设计理念是通过模块化架构降低AI应用的开发复杂度。与Python生态中的LangChain/LlamaIndex等工具类似&#xff0c;但特别为多语…...

初学 pytest 记录

安装 pip install pytest用例可以是函数也可以是类中的方法 def test_func():print()class TestAdd: # def __init__(self): 在 pytest 中不可以使用__init__方法 # self.cc 12345 pytest.mark.api def test_str(self):res add(1, 2)assert res 12def test_int(self):r…...

AI,如何重构理解、匹配与决策?

AI 时代&#xff0c;我们如何理解消费&#xff1f; 作者&#xff5c;王彬 封面&#xff5c;Unplash 人们通过信息理解世界。 曾几何时&#xff0c;PC 与移动互联网重塑了人们的购物路径&#xff1a;信息变得唾手可得&#xff0c;商品决策变得高度依赖内容。 但 AI 时代的来…...

Kafka入门-生产者

生产者 生产者发送流程&#xff1a; 延迟时间为0ms时&#xff0c;也就意味着每当有数据就会直接发送 异步发送API 异步发送和同步发送的不同在于&#xff1a;异步发送不需要等待结果&#xff0c;同步发送必须等待结果才能进行下一步发送。 普通异步发送 首先导入所需的k…...

GitFlow 工作模式(详解)

今天再学项目的过程中遇到使用gitflow模式管理代码&#xff0c;因此进行学习并且发布关于gitflow的一些思考 Git与GitFlow模式 我们在写代码的时候通常会进行网上保存&#xff0c;无论是github还是gittee&#xff0c;都是一种基于git去保存代码的形式&#xff0c;这样保存代码…...

云原生安全实战:API网关Kong的鉴权与限流详解

&#x1f525;「炎码工坊」技术弹药已装填&#xff01; 点击关注 → 解锁工业级干货【工具实测|项目避坑|源码燃烧指南】 一、基础概念 1. API网关&#xff08;API Gateway&#xff09; API网关是微服务架构中的核心组件&#xff0c;负责统一管理所有API的流量入口。它像一座…...