C#-12 转换

  • C#-12 转换已关闭评论
  • 263 次浏览
  • A+
所属分类:.NET技术
摘要

转换是接受一个类型的值并使用它作为另一个类型的等价值的过程。下列代码演示了将1个short类型的值强制转换成byte类型的值。


一 什么是转换

转换是接受一个类型的值并使用它作为另一个类型的等价值的过程。

下列代码演示了将1个short类型的值强制转换成byte类型的值。

short var1 = 5; byte var2 = 10;  var2 = (byte) var1;    //强制转换,将var1的值转换成byte类型

C#-12 转换

 

二 隐式转换

有些类型的转换不会丢失数据与精度,如将8位的值转换成16位的值是非常容易的,不会丢失精度。

C#语言会自动进行转换,称为隐式转换。

从位数更少的源转换成位数更多的目标类型时,目标中多出的位需要用0或1填充。

当从更小的无符号类型转换为更大的无符号类型时,目标类型多出的最高位都以0进行填充,这叫做零扩展。

下图演示使用零扩展将8位的10转换成16位的10:

C#-12 转换

 

对于有符号类型的转换而言,额外的高位用源表达式的符号位进行填充,这样就维持了被转换值的正确符号和大小。 

下图演示符号扩展:

C#-12 转换

 

三 显示转换和强制转换

尝试将ushort值1365转换为byte值,会导致数据丢失。

C#-12 转换

 

对于预定义类型,C#会自动将一个数据类型转换成另一个数据类型,但只是针对那些从源类型到目标类型不会发生数据丢失的情况。

而对于从源类型到目标类型转换会发生数据丢失的情况,C#不提供自动转换,就需要使用显示转换。这叫做强制转换表达式。

四 转换的类型

有很多标准的、预定义的用于数字和引用的转换。

C#-12 转换

 

 

除了标准转换,还可以为自定义类型定义隐式转换和显示转换。

装箱:将值类型转换为object类型、System.ValueType类型。

拆箱:将一个装箱的值转换为原始类型。

五 引用转换

引用类型对象有内存中的两部分组成:引用和数据。

由引用保存的那部分信息是它指向的数据类型。

引用转换接受源引用并返回一个指向堆中同一位置的引用,但是把引用标记为转换的目标类型。

下例给出两个引用变量,myVar1和myVar2,它们指向内存中的相同对象。

class Program {     static void Main(string[] args)     {         B myVar1 = new B();         A myVar2 = (A)myVar1;   //将myVar1作为A类的引用返回          Console.WriteLine(myVar1.Field1);   //正确         Console.WriteLine(myVar2.Field2);   //错误,Field2对于myVar2不可见     } }  class A { public int Field1; }  class B : A { public int Field2; }

5.1 隐式引用转换

C#可以自动实现隐式引用转换。

  • 所有引用类型都可以被隐式转换为object类型;
  • 任何类型可以隐式转换到它继承的接口;
  • 类可以隐式转换到它继承链中的任何类和它实现的任何接口。

5.2 显示引用转换

显示引用转换是从一个普通类型到一个更精确类型的引用转换。

显示转换包括:

  • 从object到任何引用类型的转换;
  • 从基类到从它继承的类的转换。

六 装箱转换和拆箱转换

6.1 装箱转换

装箱是一种隐式转换,它接受值类型的值,根据这个值在堆中创建一个完整的引用类型对象并返回对象引用。

6.2 拆箱转换

拆箱是把装箱后的对象转换回值类型对象的过程。

拆箱是显示转换。

系统在把值拆箱成ValueTypeT时执行了如下步骤:

  • 它检测到要拆箱的对象实际是ValueTypeT的装箱值;
  • 它把对象的值复制到变量。

七 用户自定义转换

除了标准转换,我们还可以为类和结构自定义隐式转换和显示转换。

 语法如下:

public static implicit operator TargetType (SourceType Identifier) {        . . .        return ObjectOfTargetType    }      

用户自定义转换的约束:

  • 只可以为类和结构定义用户自定义转换;
  • 不能重定义标准隐式转换或显示转换;
  • 对于源类型S和目标类型T,S和T必须是不同类型;
  • S和T不能通过继承关联,S和T都不能是接口类型或object类型;
  • 转换运算符必须是S或T的成员。 

implicit:隐式转换
explicit:显示转换,需要强制转换表达式

下面演示一个用户自定义转换的例子:

class Program {     static void Main(string[] args)     {         Person bill = new Person("bill", 25);         int age = bill;     //将Person对象转换为int         Console.WriteLine($"Person Info :{bill.Name},{age}");          Person none = 35;   //将int转换为Person对象         Console.WriteLine($"Person Info :{none.Name},{none.Age}");          //输出:         //Person Info :bill,25         //Person Info :none,35     } }  class Person {     public string Name;     public int Age;      public Person(string name, int age)     {         Name = name;         Age = age;     }      //将Person隐式转换为int     public static implicit operator int(Person p)     {         return p.Age;     }      //将int隐式转换为Person     public static implicit operator Person(int i)     {         return new Person("none", i);     } }

八 is运算符和as运算符

有些转换是非法的,会在运行时抛出一个InvalidCastException异常。我们可以使用Is运算符来检查转换是否会成功完成。

as运算符和强制转换运算符类似,只是它不抛出异常。如果转换失败,它返回null而不是抛出异常。

class Program {     static void Main(string[] args)     {         var student = new Student();         student.Name = "jack";         student.Age = 16;         // is 第1种用法:检测student是否能转换为Person类型,如果可以,则返回true         if (student is Person)         {             Console.WriteLine("stundent is Person");         }         // is 第2种用法:检测student是否能转换为Person类型,如果可以,则返回true,并将其转换赋值给Person类型的变量p         if (student is Person p)         {             Console.WriteLine($"Person p:{p.Name},{p.Age}");         }          // as 用法         var p1 = student as Person;         if (p1 != null)         {             Console.WriteLine($"Person p:{p1.Name},{p1.Age}");         }     } }  class Person {     public string Name;     public int Age; }  class Student : Person { }