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

if (dto.Payment == null) continue;

var entity = entries.FirstOrDefault(e => e.LedgerEntryID == dto.LedgerEntryID);

dto.Payment = entity?.Payment;

 

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

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

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

    public static implicit operator PaymentDTO(Payment payment)

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

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

Implicit和Explicit

Implicit

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

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

    public class Payment

    {

         public decimal Amount { get; set; }

    }

    public class PaymentDTO

    {

         public string AmountString { get; set; }

    }

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

        public class PaymentDTO

        {

            public string AmountString { get; set; }

            public static implicit operator PaymentDTO(Payment payment)

            {

                return new PaymentDTO

                {

                    AmountString = payment.Amount.ToString("C2")

                };

            }

        }

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

        class Program

        {

            static void Main(string[] args)

            {

                PaymentDTO dto = new Payment { Amount =  };

                Console.WriteLine(dto.AmountString);

                Console.Read();

            }

        }

Explicit

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

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

        public class PaymentDTO

        {

            public string AmountString { get; set; }

            public static explicit operator PaymentDTO(Payment payment)

            {

                return new PaymentDTO

                {

                    AmountString = payment.Amount.ToString("C2")

                };

            }

        }

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

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

        class Program

        {

            static void Main(string[] args)

            {

                PaymentDTO dto = (PaymentDTO)new Payment { Amount =  };

                Console.WriteLine(dto.AmountString);

                Console.Read();

            }

        }

总结

  • 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. linux的特殊符号与正则表达式

    第1章 linux的特殊符号 1.1 通配符 * {} 1.1.1 含义 方便查找文件 通配符是用来找文件名字的. 1.1.2  * 通过find 命令找以 .sh 结尾的文件,使用*替代文件名字. ...

  2. TOMCAT启动到一半停止如何解决

    当你的项目过大的时候,往往会导致你的TOMCAT启动时间过长,启动失败,遇到该情况可以试一下下面两招: TOmcat启动到一半的时候停止了,以下原因: 1.  tomcat启动时间超过了设置时间: 解 ...

  3. HTML知识速递

    1.html的定义 超文本标记语言(Hypertext Markup Language,HTML)通过标签语言来标记要显示的网页中的各个部分.一套规则,浏览器认识的规则 浏览器按顺序渲染网页文件,然后 ...

  4. MSSQL 常用操作

    0.GUID去除横线和变换为小写 SELECT LOWER(REPLACE(LTRIM(NEWID()),'-','')) 1.IDENTITY 函数说明 IDENTITY ( data_type [ ...

  5. HQL连接查询和注解

    HQL连接查询和注解 一:HQL连接查询 各种连接查询: 内连接:inner join或join From Entity inner [inner] join [fetch] Entity.prope ...

  6. java多线程创建-Thread,Runnable,callable和threadpool

    java创建多线程的方式有许多种,这里简要做个梳理 1. 继承Thread类 继承java.lang.Thread类,创建本地多线程的类,重载run()方法,调用Thread的方法启动线程.示例代码如 ...

  7. Vim配置及使用笔记

    Vim配置及使用笔记 安装 apt-get install vim -y 配置说明 vim /etc/vim/vimrc 在配置文件后加入这些配置项 set nu set tabstop=4 set ...

  8. AIO5程序中审批跳转条件:超过某一个值必须总经理审批

    以实际需求为例看下系统中如何设置: 客户需求:采购订单中对总金额进行限制,超过20000的话必须要经过总经理审批含税金额<20000:采购部门某个员工发起→直接主管批→财务主管知会含税金额≥20 ...

  9. spark2的编译

    0.操作系统 centos:6.4 hadoop:2.5.0-cdh5.3.6 1.为什么要编译 spark 源码? 学习spark的第一步 就应该是编译源码,后期修改和调试,扩展集成的功能模块 2. ...

  10. E:I Think I Need a Houseboat-poj

    E:I Think I Need a Houseboat 总时间限制:  1000ms 内存限制:  65536kB 描述 Fred Mapper is considering purchasing ...