C# 类型转换(知识要点归纳总结)
简介
C#是一门强类型语言,即在编译时静态类型化的,因此变量在声明后就无法再次声明,或者无法存储其它类型的值,除非把该值转化成声明的类型。当需要将一种类型变量的值复制到另一种类型的变量或参数中是,就需要类型转换。
- 隐式转换:这是一种类型安全的转换,不会导致数据丢失,不需要特殊语法。
- 显式转换(强制转换):显式转换需要强制转换运算符。在转换中可能丢失信息或者转换不成功时,必须进行强制转换。
- 用户定义的转换:可以定义一些特殊的方法来执行用户定义的转换,从而使不具有基类-派生类关系的自定义类型之间可以显式和隐式转换
- 使用帮助程序类的转换:若要在不兼容的类型之间进行转换,例如在整数与System.DateTime 对象之间转换,或者在十六进制字符串与字节数组之间转换,则可以使用 System.BitConverter 类、System.Convert 类和内置数值类型的Parse方法,例如 Int32.Parse。
具体说明
隐式转换
- 对于内置数值类型,容量小的变量中的值转换成容量大的变量中的值,此时不会出现数据截断和四舍五入而导致的信息丢失的情况;
- 派生类到基类的转换;
- 实现接口的类到接口的转换。
示例:
int num = 2147483647;
long bigNum = num;//隐式转换
class Programe
{
static void Main()
{
var classBase=new ClassBase();
var classChild=new ClassChild();
classBase=classChild;//隐式转换
}
}
class ClassChild:ClassBase
{
}
class ClassBase
{
}
class Programe
{
static void Main()
{
IDoSometing doSomething;
var classChild=new ClassChild();
doSomething=classChild;//隐式转换
}
}
class ClassChild:IDoSometing
{
//成员声明和实现
}
interface IDoSometing
{
//成员声明
}
显示转换
- 对于内置数值类型,容量大的变量中的值转换成容量小的变量中的值,此时会出现数据截断和四舍五入而导致的信息丢失的情况;
- 基类到派生类的转换;
- 接口到实现接口的类的转换。
示例:
class Test
{
static void Main()
{
double x = 1234.7;
int a;
// Cast double to int.
a = (int)x;
System.Console.WriteLine(a);
}
}
// Output: 1234
运行时的类型转换异常
在某些引用类型转换中,编译器无法确定强制转换是否会有效。 正确进行编译的强制转换操作有可能在运行时失败。 如下面的示例所示,类型强制转换在运行时失败将导致引发 InvalidCastException。
using System;
class Animal
{
public void Eat() { Console.WriteLine("Eating."); }
public override string ToString()
{
return "I am an animal.";
}
}
class Reptile : Animal { }
class Mammal : Animal { }
class UnSafeCast
{
static void Main()
{
Test(new Mammal());
// Keep the console window open in debug mode.
System.Console.WriteLine("Press any key to exit.");
System.Console.ReadKey();
}
static void Test(Animal a)
{
// Cause InvalidCastException at run time
// because Mammal is not convertible to Reptile.
Reptile r = (Reptile)a;
}
}
使用 as 和 is 运算符安全地进行强制转换
由于对象是多态的,因此基类类型的变量可以保存派生类型。 若要访问派生类型的方法,需要将值强制转换回该派生类型。 不过,在这些情况下,如果只尝试进行简单的强制转换,会导致引发 InvalidCastException 的风险。 这就是 C# 提供 is 和 as 运算符的原因。 您可以使用这两个运算符来测试强制转换是否会成功,而没有引发异常的风险。 通常,as 运算符更高效一些,因为如果可以成功进行强制转换,它会实际返回强制转换值。 而 is 运算符只返回一个布尔值。 因此,如果只想确定对象的类型,而无需对它进行实际强制转换,则可以使用 is 运算符。
class SafeCasting
{
class Animal
{
public void Eat()
{ Console.WriteLine("Eating."); }
public override string ToString()
{
return "I am an animal.";
}
}
class Mammal : Animal { }
class Giraffe : Mammal { }
class SuperNova { }
static void Main()
{
SafeCasting app = new SafeCasting();
// Use the is operator to verify the type.
// before performing a cast.
Giraffe g = new Giraffe();
app.UseIsOperator(g);
// Use the as operator and test for null
// before referencing the variable.
app.UseAsOperator(g);
// Use the as operator to test
// an incompatible type.
SuperNova sn = new SuperNova();
app.UseAsOperator(sn);
// Use the as operator with a value type.
// Note the implicit conversion to int? in
// the method body.
int i = 5;
app.UseAsWithNullable(i);
double d = 9.78654;
app.UseAsWithNullable(d);
// Keep the console window open in debug mode.
System.Console.WriteLine("Press any key to exit.");
System.Console.ReadKey();
}
void UseIsOperator(Animal a)
{
if (a is Mammal)
{
Mammal m = (Mammal)a;
m.Eat();
}
}
void UseAsOperator(object o)
{
Mammal m = o as Mammal;
if (m != null)
{
Console.WriteLine(m.ToString());
}
else
{
Console.WriteLine("{0} is not a Mammal", o.GetType().Name);
}
}
void UseAsWithNullable(System.ValueType val)
{
int? j = val as int?;
if (j != null)
{
Console.WriteLine(j);
}
else
{
Console.WriteLine("Could not convert " + val.ToString());
}
}
}