大多数编程语言都支持显示转换,也称为强制转换,它与隐式转换相呼应,比如,一般的,整型可以通过隐式转换成浮点型,而浮点型需要通过强制转换成整型:  

    int i = 32;
double d = i;//整型隐式转换成浮点型
int j = (int)d;//浮点型显示转换成整型

  目前,C#中可用的隐式转换有下面这些:

  1、所有隐式转换

  隐式转换时自动完成的,那隐式转换也支持强制转换,这无可厚非。

  2、显式数值类型转换

  显式数值转换包括:  

    1、sbyte 类型可以显式转换为 byte, ushort, uint, ulong, char.
2、byte 类型可以显式转换为 sbyte, char.
3、short 类型可以显式转换为 sbyte, byte, ushort, uint, ulong, char.
4、ushort 类型可以显式转换为 sbyte, byte, short, or char.
5、int 类型可以显式转换为 sbyte, byte, short, ushort, uint, ulong, char.
6、uint 类型可以显式转换为 sbyte, byte, short, ushort, int, char.
7、long 类型可以显式转换为 sbyte, byte, short, ushort, int, uint, ulong, char.
8、ulong 类型可以显式转换为 sbyte, byte, short, ushort, int, uint, long, char.
9、char 类型可以显式转换为 sbyte, byte, or short.
10、float 类型可以显式转换为 sbyte, byte, short, ushort, int, uint, long, ulong, char, decimal.
11、double 类型可以显式转换为 sbyte, byte, short, ushort, int, uint, long, ulong, char, float, decimal.
12、decimal 类型可以显式转换为 sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double.

  需要注意的是,数值类型在转换时,可能会丢失精度,或者抛出异常,其中转换的规则按照下面的方式进行:

  • 整型数据强制转换为另一个整型数据,它的转换依赖于是否使用了checked和unchecked上下文检测:

        如:整型(S)显式转换为整型(T)
    
        1、使用checked上下文检测时,当S数据在T所允许的范围内时,转换可以成功进行,否则抛出System.OverflowException
    2、使用unchecked上下文检测时:
    当S的位数大于T的位数时,转换时会截取到多余的高位(二进制),剩下的位数作为T数据输出
    当S的位数小于T的位数时,转换时将对S数据(二进制)进行拓展(无符号整数使用0拓展,有符号整数,如果小于0使用1拓展,否则使用0拓展),将拓展后的值作为T数据输出
    当S的位数与T的位数相等时,则不需要截取也不需要拓展,S数据直接转换成T数据
    3、未使用checked和unchecked上下文检测时,则根据编译时选择的默认的上下文检测方式(一般是unchecked)

    例如:

        //--------------------------------------checked上下文检测--------------------------------------------------
    
        long l1 = 100000L;
    int value1 = checked((int)l1); //正常转换
    int value2 = checked((int)(l1 * l1));//报错OverflowException //--------------------------------------unchecked上下文检测-------------------------------------------------- long l2 = 100000L * 100000L;//10000000000
    int value3 = unchecked((int)l2);//1410065408
    //long是64位>int的32位,l2的二进制:01001010100000010111110010000000000
    //截取掉多余的3个高位,得到剩下的32位的二进制:01010100000010111110010000000000,即1410065408 sbyte b = -1;//有符号8位
    uint value4 = unchecked((uint)b);//4294967295
    //sbyte是8位<uint的32位,b的二进制:1111111111111111
    //因为sbyte是有符号整数且b<0,所以使用1拓展高位得到32位的二进制:11111111111111111111111111111111,即4294967295 uint ui = 3147483647;
    int value5 = unchecked((int)ui);//-1147483649
    //uint是32位=int的32位,ui的二进制:10111011100110101100100111111111
    //所以直接就是int的二进制:10111011100110101100100111111111,即-1147483649
  • decimal浮点数强制转换成整型数据时,会向零取整舍弃小数部分,如果取整后的值不在转换类型所允许的范围内,将会抛出System.OverflowException,例如:
        decimal d1 = 1.6m;
    decimal d2 = -1.6m;
    decimal d3 = 314m;
    sbyte b1 = (sbyte)d1;//1
    sbyte b2 = (sbyte)d2;//-1
    sbyte b3 = (sbyte)d3;//报错System.OverflowException
  • float和double强制转换成整型数据时,依赖于是否使用了checked和unchecked上下文检测:
        1、使用checked上下文检测时:
    如果float或者double值是NaN或者无穷值(NegativeInfinity和PositiveInfinity),则会抛出System.OverflowException
    否则将float或者double值向零取整舍弃小数部分,如果取整后的值不在整数类型允许的范围内,则会抛出System.OverflowException
    2、使用unchecked上下文检测时:
    如果float或者double值是NaN或者无穷值(NegativeInfinity和PositiveInfinity),转换会取消,返回整型的默认值
    否则将float或者double值向零取整舍弃小数部分,如果取整后的值不在整数类型允许的范围内,转换会取消,返回整型的默认值(这一点官方文档说的不准确,看下面的例子
    3、未使用checked和unchecked上下文检测时,则根据编译时选择的默认的上下文检测方式(一般是unchecked)

    例如:

        double d1 = double.NaN;
    double d2 = 1.6d;
    double d3 = -1.6d;
    double d4 = 3147483647.25d;
    double d5 = 314.25d; //--------------------------checked上下文检测---------------------------------- sbyte b1 = checked((sbyte)d1);//报错System.OverflowException
    sbyte b2 = checked((sbyte)d2);//1
    sbyte b3 = checked((sbyte)d3);//-1
    sbyte b4 = checked((sbyte)d4);//报错System.OverflowException //--------------------------unchecked上下文检测-------------------------------- sbyte b5 = unchecked((sbyte)double.PositiveInfinity); //0
    sbyte b6 = unchecked((sbyte)2.5d); //2
    sbyte b7 = unchecked((sbyte)-3.5d); //-3
    sbyte b8 = unchecked((sbyte)314.25d); //0
    byte b9 = unchecked((byte)257.25d); //0
    short b10 = unchecked((short)3147483647.25d); //0
    int b11 = unchecked((int)3147483647.25d); //0 //下面的和官方文档的是不一样(有空再找找原因,可能是编译时和运行时的设置问题)
    int b12 = unchecked((int)d4); //-2147483648
    sbyte b13 = unchecked((sbyte)d5); //58
  • double强制转换成float时,遵从规则:
        1、一般情况下,double值会通过向最接近的float值进行取舍(非四舍五入),保证精度丢失比较小
    2、如果一个double值无限趋向于0,当精度超过float所允许的精度时(float.Epsilon),会将+0或者-0作为结果返回,这取决于double是正数还是负数
    3、如果一个double值非常大,大于float所允许的范围时,会将无穷大返回(float.NegativeInfinity或者float.PositiveInfinity,这取决于double是正数还是负数)

    例如:

        double d0 = 3.1415d;
    double d1 = 3.141592653589793d;
    double d2 = double.NaN;
    double d3 = 3.14E-100d;
    double d4 = -3.14E-100d;
    double d5 = double.MaxValue;
    double d6 = double.MinValue; float f0 = (float)d0;//3.1415
    float f1 = (float)d1;//3.1415927
    float f2 = (float)d2;//NaN
    float f3 = (float)d3;//+0
    float f4 = (float)d4;//-0
    float f5 = (float)d5;//float.PositiveInfinity
    float f6 = (float)d6;//float.NegativeInfinity
  • double、float强制转换成decimal时,遵从规则:

        1、一般的,double和float值会直接转换成decimal,当小数据超过28位时,如果需要会自动进行取舍
    2、如果double和float值太小而趋向于0,则会直接返回0
    3、如果double和float值是NaN、无穷大、或者是超过decimal运行的范围,那么将会抛出System.OverflowException

    例如:

        double d0 = 3.1415d;
    double d1 = 3.14159265358979323d;
    double d2 = double.NaN;
    double d3 = 3.14E-200d;
    double d4 = -3.14E-200d;
    double d5 = double.MaxValue;
    double d6 = double.MinValue; decimal value0 = (decimal)d0;//3.1415
    decimal value1 = (decimal)d1;//3.14159265358979
    decimal value2 = (decimal)d2;//抛出System.OverflowException
    decimal value3 = (decimal)d3;//0
    decimal value4 = (decimal)d4;//0
    decimal value5 = (decimal)d5;//抛出System.OverflowException
    decimal value6 = (decimal)d6;//抛出System.OverflowException
  • decimal强制转换成double或者float时,都可以转换成功,不会抛出任何异常,但是可能会造成精度的丢失,例如:

        decimal d0 = 3.1415m;
    decimal d1 = 3.14159265358979323m; float value0 = (float)d0;//3.1415
    float value1 = (float)d1;//3.1415927

  3、显式枚举类型转换

  显式枚举类型转换包括:  

    1、sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimal 可以显式转换为任何枚举类型.
2、任何枚举类型可以显式的转换为 sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimal.
3、任意两个枚举类型之间可以进行显式转换.

  其实,枚举类型底层还是整型数据,也就是说枚举类型的显示转换本质上还是整型数据的强制转换问题。

  4、显式可空类型转换

  显式可空类型转换指的是,如果一个值类型S可以显式的转换成另一个值类型T,那么S和T还存在下列显式的转换:  

    1、S? 可通过显式转换成 T?,如果S?的值是null,那么转换后的T?也是null,否则等价于 S?->S->T->T? 的过程
2、S 可通过显式转换成 T?,这等价于 S->T->T? 的过程
3、S? 可通过显式转换成 T,如果S?的值是null,则会抛出System.InvalidOperationException,否则等价于 S->T 的过程

  5、显式引用转换

  显式引用转换包括:  

    1、object 和 dynamic 可以显式引用转换成任何其他的引用类型
2、基类(父类)可以通过显式引用转换成一个子类
3、任何一个非sealed的类可以通过显式引用转换成任何一个接口,不管这个类是否实现了这个接口
4、任何一个接口可以通过显式引用转换成任何一个非sealed的类,不管这个类是否实现了这个接口
5、任何一个接口可以通过显式引用转换成任何一个接口,不管它们是否是父子接口关系
6、如果任意两个引用类型之间存在一个显式引用转换,那么它们相同维度的数组之间也可以通过显式引用转换
7、System.Array即它所实现的接口(如System.Collections.IList),可以显式引用转换为任意的数组类型
8、如果一个类型S到另一个类型T存在显式引用转换,那么S的一维数组S[]到System.Collections.Generic.IList<T>及它的父接口(如System.Collections.Generic.ICollection<T>)也存在显式引用转换
9、如果一个类型S到另一个类型T存在显式引用转换,那么System.Collections.Generic.IList<S>及它的父接口(如System.Collections.Generic.ICollection<S>)到T的一维数组T[]也存在显式引用转换
10、System.Delegate及它所实现的所有接口可以显式引用转换成任意的委托类型
11、如果一个引用类型T1存在显式引用转换到引用类型T2,T2存在标识转换到T3,那么T1也可以通过显式引用转换成T3
12、如果一个引用类型T1存在显式引用转换到一个接口或者委托类型T2,而T2与T3之间存在协变、逆变或者不变,那么T1也可以通过显式引用转换成T3
14、如果D<X1,X2,...,Xn>是一个泛型委托类型,当Xi满足下面条件之一时,那么D<S1,S2...Sn>到D<T1,T2...Tn>存在显式引用转换:
Xi是不变,且Si到Ti相同
Xi是协变,且Si到Ti存在显式和隐式的标识或引用转换
Xi是逆变,且Si和Ti要么相同,要么都是引用类型

  简单的例子:  

    public class Parent { }
public class Child : Parent { }
public interface IPerson { }
public interface IAnimal { } object obj = null;
Parent parent = (Parent)obj; //object 和 dynamic 可以显式引用转换成任何其他的引用类型
Child child = (Child)parent; //基类(父类)可以通过显式引用转换成一个子类
IPerson person = (IPerson)child; //任何一个非sealed的类可以通过显式引用转换成任何一个接口,不管这个类是否实现了这个接口
Exception exception = (Exception)person;//任何一个接口可以通过显式引用转换成任何一个非sealed的类,不管这个类是否实现了这个接口
IAnimal animal = (IAnimal)person; //任何一个接口可以通过显式引用转换成任何一个接口,不管它们是否是父子接口关系 //如果任意两个引用类型之间存在一个显式引用转换,那么它们相同维度的数组之间也可以通过显式引用转换
IAnimal[] animals = (IAnimal[])new IPerson[0];
IPerson[,] persons = (IPerson[,])new IAnimal[1, 2]; //System.Array即它所实现的接口(如System.Collections.IList),可以显式引用转换为任意的数组类型
Array array = null;
IList list = null;
int[] ints = (int[])array;
double[,] doubles = (double[,])list; //如果一个类型S到另一个类型T存在显式引用转换,那么S的一维数组S[]到System.Collections.Generic.IList<T>及它的父接口(如System.Collections.Generic.ICollection<T>)也存在显式引用转换
Parent[] parents = null;
IList<Child> children = (IList<Child>)parents;
ICollection<Child> children1 = (ICollection<Child>)parents;
//反之亦然:如果一个类型S到另一个类型T存在显式引用转换,那么System.Collections.Generic.IList<S>及它的父接口(如System.Collections.Generic.ICollection<S>)到T的一维数组T[]也存在显式引用转换
parents = (Parent[])children;
parents = (Parent[])children1; //System.Delegate及它所实现的所有接口可以显式引用转换成任意的委托类型
Delegate @delegate = null;
ICloneable cloneable = null;
Func<int> func = (Func<int>)@delegate;
Action action = (Action)cloneable; //如果一个引用类型T1存在显式引用转换到一个接口或者委托类型T2,而T2与T3之间存在协变、逆变或者不变,那么T1也可以通过显式引用转换成T3
Array array1 = new Child[0];
IEnumerable<Parent> parents1 = (IEnumerable<Parent>)array1;//System.Array可以显式引用转换成Child[],而Child[]到IEnumerable<Parent>存在协变 //如果D<X1,X2,...,Xn>是一个泛型委托类型,当Xi满足下面条件之一时,那么D<S1,S2...Sn>到D<T1,T2...Tn>存在显式引用转换:
//Xi是不变,且Si到Ti相同
//Xi是协变,且Si到Ti存在显式和隐式的标识或引用转换
//Xi是逆变,且Si和Ti要么相同,要么两种引用类型
Func<Parent, Child> func1 = p => (Child)p;
Func<Child, Parent> func2 = (Func<Child, Parent>)func1;

  注:因为显式引用转换是在运行时检查的,所以我们尽量保证待转换的值是null或者是可转换的,否则将会抛出System.InvalidCastException

  6、拆箱转换

  装箱转换允许将一个值类型包装成引用类型来使用,而拆箱转换则相反,将引用类型拆箱得到里面的值类型,目前拆箱转换包括:  

    1、object 可以拆箱转换成值类型
2、System.ValueType 可以拆箱转换成任何值类型.
3、任何接口可以拆箱转换成实现了这个接口的非空值类型
4、任何接口可以拆箱转换成实现了这个接口的值类型的可空类型
5、System.Enum可以拆箱转换成任何枚举类型
6、System.Enum可以拆箱转换成任何枚举类型的可空类型

  例如

    object obj = 1;
ValueType value = 2L;
int i = (int)obj; //object 可以拆箱转换成值类型
long l = (long)value; //System.ValueType 可以拆箱转换成任何值类型 IFormattable formattable = 3.14f;
float s = (float)formattable; //任何接口可以拆箱转换成实现了这个接口的非空值类型
float? nullable_s = (float?)formattable;//任何接口可以拆箱转换成实现了这个接口的值类型的可空类型 Enum @enum = DayOfWeek.Monday;
DayOfWeek dayOfWeek1 = (DayOfWeek)@enum; //System.Enum可以拆箱转换成任何枚举类型
DayOfWeek? dayOfWeek2 = (DayOfWeek?)@enum; //System.Enum可以拆箱转换成任何枚举类型的可空类型

  注:因为拆箱转换是在运行时检查的,说我们要尽量保证它是可拆箱的,如果将一个null值拆箱给一个非空的值对象,那么将会抛出System.NullReferenceException,如果拆箱的值不是合适的类型,那么将会抛出System.InvalidCastException。

  7、显式动态转换

  显式动态转换指的是dynamic可以显式转换成任意的其他类型,需要注意的是,它是运行时检查转换的,如果转换失败,将会抛出异常。

    dynamic @dynamic = 3.14f;
long l = (long)@dynamic;//可以显式动态转换
int i = @dynamic;//运行时将报错,float不能通过隐式转换成int

  一般的,如果dynamic对象保存的类型不是所需要的类型,那么它会先将dynamic转换陈给对象,再由对象转换成所需要的类型,也就是说,如果类型S可以通过显式转换成T,那么S也可以通过显式动态转换成T。

  8、涉及类型参数的显式转换

  这里指的一般是泛型参数的转换,其实显式转换作用在泛型类型上,参考下面的例子:  

    public class Parent
{
public static explicit operator string(Parent parent) => parent?.ToString();
}
public class Demo
{
public int E<T>(T t)
{
return (int)t;//报错,因为不知道泛型T是什么类型
}
public int F<T>(T t)
{
return (int)(object)t;//这样写可以不报错
}
public string G<T>(T t) where T : Parent
{
return (string)t;//可以转换,Parent类具有自定义转换到string
} }

  9、用户自定义的显式转换

  C#允许用户可自定义类型或者结构的自定义转换,可以看看:C#自定义转换(implicit 或 explicit)

  参考文档:https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/language-specification/conversions#explicit-conversions

C#中的显式转换的更多相关文章

  1. C#中的Explicit和Implicit

    今天在Review一个老项目的时候,看到一段奇怪的代码. if (dto.Payment == null) continue; var entity = entries.FirstOrDefault( ...

  2. OpenCv Mat操作总结

    Author:: Maddock Date: 2015-03-23 16:33:49 转载请注明出处:http://blog.csdn.net/adong76/article/details/4053 ...

  3. C# 语言规范_版本5.0 (第6章 转换)

    1. 转换 转换(conversion) 使表达式可以被视为一种特定类型.转换可导致将给定类型的表达式视为具有不同的类型,或其可导致没有类型的表达式获得一种类型.转换可以是隐式的 (implicit) ...

  4. 面向对象编程技术的总结和理解(c++)

    目录树 1.继承 1.1 基类成员在派生类中的访问属性 1.2继承时导致的二义性 1.3 多基继承 2.虚函数的多态 2.1虚函数的定义 2.2派生类中可以根据需要对虚函数进行重定义 2.3 虚函数的 ...

  5. C#6.0语言规范(六) 转换

    转换能够被视为是一个特定类型的表达式.转换可能会导致给定类型的表达式被视为具有不同的类型,或者它可能导致没有类型的表达式获取类型.转换可以是隐式或显式的,这决定了是否需要显式转换.例如,从类型int到 ...

  6. 【Try Kotlin】Kotlin Koans 代码笔记

    Kotlin Koans 心印 Introduction 1.Hello, world! Simple Functions Take a look at function syntax and mak ...

  7. Python开源框架

    info:更多Django信息url:https://www.oschina.net/p/djangodetail: Django 是 Python 编程语言驱动的一个开源模型-视图-控制器(MVC) ...

  8. C#中的类型转换-自定义隐式转换和显式转换

    目录 前言 基础知识 示例代码 实际应用 问题 答案 报错 用户定义的转换必须是转换成封闭类型,或者从封闭类型转换 参考 其他 应用和设计 读音 参考 前言 有时我们会遇到这么一种情况:在json数据 ...

  9. C#学习笔记9:C#中的变量、转义符、显式转换和隐式转换

    1.变量的特性:可以重复的赋值 int a=4;  a=9; 2.常量:const int  number=10:这个常量不可变 如果你声明的变量,不想被其他人修改,那么就修饰为常量 声明在类的下面, ...

随机推荐

  1. CentOS 初体验三: Yum 安装、卸载软件

    一:Yum 简介 Yum(全称为 Yellow dog Updater, Modified)是一个在Fedora和RedHat以及CentOS中的Shell前端软件包管理器.基于RPM包管理,能够从指 ...

  2. linux shell学习之shell流程控制

    在linux shell编程中,流程控制结构与语句,也算是shell脚本中的重点了,不了解的朋友,跟随脚本小编一起来学习下吧. linux控制流结构学习. 一,shell控制流结构 1.控制结构   ...

  3. BeanDefinitionLoader spring Bean的加载器

    spring 容器注册bean , 会把bean包装成beanDefinition 放进spring容器中,beanDefinitionLoader就是加载bean的类 . 一.源码 class Be ...

  4. synchronized底层浅析(二)

    一张图了解锁升级流程:

  5. 【C/C++】指针,传参,引用的一些个人理解。

    (以下均为个人理解) 函数访问的传参两种方式大致为: 值传递: 地址传递. 但是实际上可以都理解为,传进来的[形参]是主函数里的实参值的[一种复制]. 举个例子,哪怕我们将地址作为子函数的输入变量,形 ...

  6. 避免警报疲劳:每个 K8s 工程团队的 8 个技巧

    避免警报疲劳:每个 K8s 工程团队的 8 个技巧 监控 Kubernetes 集群并不容易,警报疲劳通常是一个问题.阅读这篇文章,了解减少警报疲劳的有用提示. 如果您是随叫随到团队的一员,您可能知道 ...

  7. podman wsl2在windows重启后出错

    1. error joining network namespace for container 如果没有先停止容器就重启windows,极大概率就会出现这个问题 解决方法 先停止停止的容器再启动已退 ...

  8. Jsp/servlet分页五要素

    分页5要素: * 1)pageIndex 当前页 * 2)startIndex 从第几条数据开始 * 3)countAll 总条目数 * 4)pageSize 每页大小 * 5)pageCount 总 ...

  9. Mysql脚本 优化检测

    下载地址: wget https://launchpad.net/mysql-tuning-primer/trunk/1.6-r1/+download/tuning-primer.sh 安装依赖: y ...

  10. inndy_rop

    又学习到了一个新知识 拿到题目例行检查,发现是32位的程序,放入ida中 进入main看到了一个overflow函数进入查看 存在明显的栈溢出,看到题目知道要用rop来做,但是完全没有思路, 后来发现 ...