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}
}

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

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

相关文章

[HCIE]vxlan --静态隧道

实验目的:1.pc2与pc3互通&#xff08;二层互通&#xff09;&#xff1b;2.pc1与pc3互通&#xff08;三层互通&#xff09; 实验说明&#xff1a;sw1划分vlan10 vlan20 ;sw2划分vlan30&#xff1b;上行接口均配置为Trunk 实验步骤&#xff1a; 1.配置CE1/CE2/CE3环回口互通&a…

百卓Smart管理平台 uploadfile.php 文件上传漏洞(CVE-2024-0939)

免责声明&#xff1a;文章来源互联网收集整理&#xff0c;请勿利用文章内的相关技术从事非法测试&#xff0c;由于传播、利用此文所提供的信息或者工具而造成的任何直接或者间接的后果及损失&#xff0c;均由使用者本人负责&#xff0c;所产生的一切不良后果与文章作者无关。该…

day39 Bootstrap——容器简括

前言 前言Bootstrap5 容器容器内边距容器的边框和颜色响应式容器 前言 Bootstrap&#xff0c;来自 Twitter&#xff0c;是目前最受欢迎的前端框架。Bootstrap 是基于 HTML、CSS、JAVASCRIPT 的&#xff0c;它简洁灵活&#xff0c;使得 Web 开发更加快捷。 Bootstrap5 容器 B…

php基础学习之分支结构和循环结构(不细讲,来对比一下和两大常用高级编程语言(C++/Java)的细微区别以便记忆)

分支结构 常见分支结构 编程语言常见分支结构有&#xff1a; if语句if-else语句if-elseif-else语句switch语句 其中&#xff0c;除了if-elseif-else语句外&#xff0c;另外3中分支语句在php中和C/Java是一模一样的&#xff01; 而if-elseif-else的唯一不同点就在&#xff0c;【…

java实现多级目录树(递归实现)

一.应用场景 有时候需要我们后台给前台传树结构的数据&#xff0c;要怎么查询? 怎么返回数据呢&#xff1f; 二.数据库表设计以及数据内容(以部门举例) id 主键 parent_id 父级部门id depart_name 部门名词 sort 部门排序三.实体类 Data public…

LeetCode、72. 编辑距离【中等,二维DP】

文章目录 前言LeetCode、72. 编辑距离【中等&#xff0c;二维DP】题目链接与分类二维DP 资料获取 前言 博主介绍&#xff1a;✌目前全网粉丝2W&#xff0c;csdn博客专家、Java领域优质创作者&#xff0c;博客之星、阿里云平台优质作者、专注于Java后端技术领域。 涵盖技术内容…

幻兽帕鲁服务器配置参数说明(Palworld官方汉化)

创建幻兽帕鲁服务器配置参数说明&#xff0c;Palworld服务器配置参数与解释&#xff0c;阿腾云atengyun.com分享&#xff1a; 自建幻兽帕鲁服务器教程&#xff1a; 阿里云教程 https://t.aliyun.com/U/bLynLC腾讯云教程 https://curl.qcloud.com/oRMoSucP 幻兽帕鲁服务器 幻…

34 张图详解网络设备知识

网络其实很简单&#xff0c;就是一堆设备连接在一起&#xff0c;然后在上面跑各种网络协议&#xff0c;实现设备之间的网络互通。其中第一步便是把所有设备按照一定的规则连接起来。这些设备可能是路由器、交换机、防火墙等网络设备&#xff0c;也可能是服务器、电脑、手机等需…

Pb协议的接口测试

Protocol Buffers 是谷歌开源的序列化与反序列化框架。它与语言无关、平台无关、具有可扩展的机制。用于序列化结构化数据&#xff0c;此工具对标 XML &#xff0c;支持自动编码&#xff0c;解码。比 XML 性能好&#xff0c;且数据易于解析。更多有关工具的介绍可参考官网。 P…

ClickHouse--07--SQL DDL 操作

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 SQL DDL 操作1 创建库2 查看数据库3 删除库4 创建表5 查看表6 查看表的定义7 查看表的字段8 删除表9 修改表9.1 添加列9.2 删除列9.3 清空列9.4 给列修改注释9.5 修…

攻防世界——re2-cpp-is-awesome

64位 我先用虚拟机跑了一下这个程序&#xff0c;结果输出一串字符串flag ——没用 IDA打开后 F5也没有什么可看的 那我们就F12查看字符串找可疑信息 这里一下就看见了 __int64 __fastcall main(int a1, char **a2, char **a3) {char *v3; // rbx__int64 v4; // rax__int64 v…

I.MX6U C语言运行环境构建及驱动开发格式

1.设置处理器模式 设置6ULL处于SVC模式下。设置下CPSR寄存器的bit4-0,也就是M[4:0]为100110x13.。读写状态寄存器需要用到MRS和MSR指令。MRS将CPSR寄存器数据读出到通用寄存器里面&#xff0c;MSR指令将通用寄存器的值写入到CPSR寄存器里面去。 2.设置SP指针 SP可以指向内部…