今天在Review一个老项目的时候,看到一段奇怪的代码。

  1. if (dto.Payment == null) continue;
  2.  
  3. var entity = entries.FirstOrDefault(e => e.LedgerEntryID == dto.LedgerEntryID);
  4.  
  5. dto.Payment = entity?.Payment;

 

其中dto.Payment是一个PaymentDTO类的实例,entity?.Payment是一个Payment类的实例,PaymentDTO类和Payment类没有子父关系,所以不存在子类和父类之间的隐式转换。

奇怪的是Visual Studio的编译器没有提示任何编译错误。

打开PaymentDTO类的定义之后,发现了以下方法签名。

  1. public static implicit operator PaymentDTO(Payment payment)

从方法签名上看,这就是重写PaymentDTO类型的操作符,但并不是我以前常用的+,-,*,/, ==等。

查询MSDN之后,才了解到implicit和explicit是一对转换操作符。

Implicit和Explicit

Implicit

Implicit关键字用于声明隐式的用户定义类型转换运算符。它可以实现2个不同类的隐式转换 ,提高代码的可读性。但是需要注意使用隐式转换操作符之后,在编译时会跳过异常检查,所以隐式转换运算符应当从不引发异常并且从不丢失信息,否则在运行时会出现一些意想不到的问题。

例如当前PaymentDTO和Payment的定义如下

  1. public class Payment
  2.  
  3. {
  4.  
  5. public decimal Amount { get; set; }
  6.  
  7. }
  8.  
  9. public class PaymentDTO
  10.  
  11. {
  12.  
  13. public string AmountString { get; set; }
  14.  
  15. }

如果需要将Payment隐式转换成PaymentDTO, 仅需声明PaymentDTO的隐式转换运算符

  1. public class PaymentDTO
  2.  
  3. {
  4.  
  5. public string AmountString { get; set; }
  6.  
  7. public static implicit operator PaymentDTO(Payment payment)
  8.  
  9. {
  10.  
  11. return new PaymentDTO
  12.  
  13. {
  14.  
  15. AmountString = payment.Amount.ToString("C2")
  16.  
  17. };
  18.  
  19. }
  20.  
  21. }

调用时只需要直接赋值就可以

  1. class Program
  2.  
  3. {
  4.  
  5. static void Main(string[] args)
  6.  
  7. {
  8.  
  9. PaymentDTO dto = new Payment { Amount = };
  10.  
  11. Console.WriteLine(dto.AmountString);
  12.  
  13. Console.Read();
  14.  
  15. }
  16.  
  17. }

Explicit

Explicit关键字声明必须通过转换来调用的用户定义的类型转换运算符。不同于隐式转换,显式转换运算符必须通过转换的方式来调用,如果缺少了显式的转换,在编译时就会产生错误。

例如现在我们将前面PaymentDTO类中定义的转换操作符从Implicit变为Explicit

  1. public class PaymentDTO
  2.  
  3. {
  4.  
  5. public string AmountString { get; set; }
  6.  
  7. public static explicit operator PaymentDTO(Payment payment)
  8.  
  9. {
  10.  
  11. return new PaymentDTO
  12.  
  13. {
  14.  
  15. AmountString = payment.Amount.ToString("C2")
  16.  
  17. };
  18.  
  19. }
  20.  
  21. }

这时候由于Main方法中没有显式转换,所以编译器出错,提示Cannot implicitly convert type 'ExplicitImplicit.Payment' to 'ExplicitImplicit.PaymentDTO'. An explicit conversion exists (are you missing a cast?)

如果想要编译器通过编译, 只需要做一个显示转换即可

  1. class Program
  2.  
  3. {
  4.  
  5. static void Main(string[] args)
  6.  
  7. {
  8.  
  9. PaymentDTO dto = (PaymentDTO)new Payment { Amount = };
  10.  
  11. Console.WriteLine(dto.AmountString);
  12.  
  13. Console.Read();
  14.  
  15. }
  16.  
  17. }

总结

  • Implicit提高了代码的可读性,但程序员需要自己保证转换不引发异常且不丢失信息
  • Explicit可阻止编译器静默调用可能产生意外后果的转换操作。
  • 前者更易于使用,后者能向阅读代码的每个人清楚地指示您要转换类型

C#中的Explicit和Implicit的更多相关文章

  1. C#中的explicit和implicit了解一下吧

    今天在研究公司项目框架的时候看到了下面的用法,public static implicit operator JsonData(int data);.貌似很久没用过这种隐式转换的写法了,因此重新温习一 ...

  2. 【RS】CoupledCF: Learning Explicit and Implicit User-item Couplings in Recommendation for Deep Collaborative Filtering-CoupledCF:在推荐系统深度协作过滤中学习显式和隐式的用户物品耦合

    [论文标题]CoupledCF: Learning Explicit and Implicit User-item Couplings in Recommendation for Deep Colla ...

  3. C#中转换运算符explicit、implicit、operator、volatile研究

    C#中的这个几个关键字:explicit.implicit与operator,估计好多人的用不上,什么情况,这是什么?字面解释:explicit:清楚明白的;易于理解的;(说话)清晰的,明确的;直言的 ...

  4. operator、explicit与implicit

    说这个之前先说下什么叫隐式转换和显示转换 1.所谓隐式转换,就是系统默认的转换,其本质是小存储容量数据类型自动转换为大存储容量数据类型. 例如:float f = 1.0: double d=f:这样 ...

  5. explicit和implicit

    explicit是C++中的一个关键字,只用于修饰只有一个参数的构造函数: class A{ explicit A(const T obj); }; 该关键字告诉编译器该类只能显式的转换,不能隐式(i ...

  6. C++中的explicit

    首先, C++中的explicit关键字只能用于修饰只有一个参数的类构造函数, 它的作用是表明该构造函数是显示的, 而非隐式的, 跟它相对应的另一个关键字是implicit, 意思是隐藏的,类构造函数 ...

  7. C++中的explicit关键字的用法

    一.explicit作用: 在C++中,explicit关键字用来修饰类的构造函数,被修饰的构造函数的类,不能发生相应的隐式类型转换,只能以显示的方式进行类型转换. 二.explicit使用注意事项: ...

  8. C++中关键字explicit的作用

    C++中, 一个参数的构造函数(或者除了第一个参数外其余参数都有默认值的多参构造函数), 承担了两个角色. 1 是个构造器 ,2 是个默认且隐含的类型转换操作符. 所以, 有时候在我们写下如 AAA ...

  9. explicit 和 implicit 的用法

    explicit 和 implicit 属于转换运算符,如用这两者可以让我们自定义的类型支持相互交换 explicti 表示显式转换,如从 A -> B 必须进行强制类型转换(B = (B)A) ...

随机推荐

  1. 一次线上Mysql数据库崩溃事故的记录

    文章简介 工作这几年,技术栈在不断更新,项目管理心得也增加了不少,写代码的速度也在提升,感觉很欣慰,毕竟是在一直进步,但是过程中也有许许多多的曲折,也踩过了数不尽的坑坑洼洼,从一个连百度都不知道用的萌 ...

  2. Azure ASM虚拟机部署“安全扩展”

    Azure虚拟机,默认情况下没有安装杀毒软件.如果您有此需求可以通过Azure 扩展进行安装,有关Azure反恶意软件的官方说明请参考:https://docs.azure.cn/zh-cn/secu ...

  3. 解决Qt编译动态链接库could not find or load the Qt platform plugin "windows" in.问题

    最近用Qt5做了一个项目的界面,在编译成可执行文件EXE之后,运行文件,提示: This application failed to start because it could not find o ...

  4. javascript 可多选的下拉框 multiselect

    首先引用一个写的很好的博客http://www.cnblogs.com/landeanfen/p/5013452.html 我使用的是bootstrap-multiselect,实现功能是 选择下拉框 ...

  5. 单元测试 Qunit

    http://api.qunitjs.com/category/assert/    测试方法   选中 "Check for Globals" 会暴露全局对象,看你的代码会不会无 ...

  6. Chrome DevTools 开发者工具 技巧 调试

    https://developers.google.com/chrome-developer-tools/docs/tips-and-tricks   1.console面板多行输入 Shift +  ...

  7. SQL Server 审计

    审计(Audit)用于追踪和记录SQL Server实例或数据库中发生的事件,审计主要包括审计对象(Audit)和审计规范(Audit Specification),创建审计首先需要创建一个SQL S ...

  8. 用cmd命令创建oracle 数据库、用户和表空间

    Win+R调查运行窗口,输入cmd回车 连接到本地oracle库 创建名为"SXSJ"的表空间,其初始大小为512M,支持自动扩展,每次增量为32M: create tablesp ...

  9. 数据库之Oracle——初级

    世上岂无千里马,人中难得九方皋: 酒船鱼网归来是,花落故溪深一篙. 关于数据库的第一篇博客,这是我的第二次,人生第二春,什么也不想说,静静的开始吧,至于为什么写唐诗,请看第一篇文章! Oracle 初 ...

  10. [转]查询 SQL Server 系统目录常见问题

    查询 SQL Server 系统目录常见问题 http://msdn.microsoft.com/zh-cn/library/ms345522.aspx#_FAQ4 下列部分按类别列出常见问题. 数据 ...