初学c#经常为这几种数据类型转换方式而迷茫,为了彻底搞清它们之间的区别和优缺点,结合网上前辈总结的资料和自己的动手验证,在此写出来,一方面,为那些跟我有过相似经历的朋友们搜索资料的时候能提供一点微小的帮助,另一方面,希望前辈们路过的时候指导一下,看哪里有不合适的地方。
众所周知,C#是一门强类型语言,对类型要求比较严格,但是在一定的条件下是可以相互转换的,如将int型数据转换成double型数据。C#允许使用两种转换方式:隐式转换和显式转换。
1、隐式转换
隐式转换就是系统默认的、不需要加以声明就可以进行的转换。隐式转换不要求在源代码中使用任何特殊语法,编译器自动执行隐式强制转换。在隐式转换过程中,编译器无需对转换进行详细检查就能够安全地执行转换。隐式强制转换也称为“扩展转换“,因为要将窄数据类型转换为宽数据类型,且还将确保不会在转换过程中丢失数据。(注意:(1)转换前后的类型必须相兼容 (例如:int和double (2)、隐式数值转换实际上就是从低精度的数值类型到高精度的数值类型的转换,即小的类型转大的类型)
int a = 10;
double b = a;//隐式转换
2、显式转换
显式类型转换,又叫强制类型转换。与隐式转换正好相反,显式转换需要用户明确地指定转换的类型。显式转换包括所有的隐式转换,也就是说把任何系统允许的隐式转换写成显式转换的形式都是允许的。用()实现显示转换,这表示,把转换的目标类型名放在要转换的值之前的圆括号中。
long val = 30000;
int i = (int)val;//显式转换
提醒:
(1)、显式转换可能会导致错误。进行这种转换时编译器将对转换进行溢出检测。如果有溢出说明转换失败,就表明源类型不是一个合法的目标类型。无法进行类型转换。
(2)、强制类型转换会造成数据精度丢失。
3、通过方法进行类型转换
(1)、使用ToString()方法。所有类型都继承了Object基类,所以都有ToString()这个方法(转化成字符串的方法)。
int i=200;
string s=i.ToString();
//这样字符串类型变量s的值就是”200” 。
(2)、通过int.Parse()方法转换,参数类型只支持string类型。注意:使用该方法转换时string的值不能为NULL,不然无法通过转换;另外string类型参数也只能是各种整型,不能是浮点型,不然也无法通过转换 (例如int.Parse("2.0")就无法通过转换)。
int i;
i = int.Parse("100");
(3)、通过int.TryParse()方法转换,该转换方法与int.Parse()转换方法类似,不同点在于int.Parse()方法无法转换成功的情况该方法能正常执行并返回0。也就是说int.TryParse()方法比int.Parse()方法多了一个异常处理,如果出现异常则返回false,并且将输出参数返回0。
int i;
string s = null;
int.TryParse(s,out i);
bool isSucess=int.TryParse("12", out i);//输出值为12;True
bool isSucess=int.TryParse("ss", out i);//输出值为0;False
bool isSucess=int.TryParse("", out i);//输出值为0;False
(4)、通过Convert类进行转换,Convert类中提供了很多转换的方法。使用这些方法的前提是能将需要转换的对象转换成相应的类型,如果不能转换则会报格式不对的错误(即前提为面上要过得去例如string类型的“666”可以转换为整数型666,string类型的“666aaa”却转换不成整数型 )。
static void Main(string[] args)
{
float num1=82.26f;
int integer,num2;
string str,strdate;
DateTime mydate=DateTime.New;
//Convert类的方法进行转换
integer=Convert.ToInt32(num1);
str=Convert.ToString(num1);
strdate=Convert.ToString(mydate);
num2=Convert.ToInt32(mydate);
Console.WriteLine("转换为整型数据的值{0}",integer);
Console.WriteLine("转换为字符串{0},str");
Console.WriteLine("日期型数据转换为字符串值为{0}",strdate);
Console.ReadKey();
}
附:Convert类常用的类型转换方法
方法 | 说明 |
Convert.ToInt32() | 转换为整型(int) |
Convert.ToChar() | 转换为字符型(char) |
Convert.ToString() | 转换为字符串型(string) |
Convert.ToDateTime() | 转换为日期型(datetime) |
Convert.ToDouble() | 转换为双精度浮点型(double) |
Conert.ToSingle() | 转换为单精度浮点型(float) |
注意:以Int类型为例,int.Parse,Convert.ToInt和int.TryParse的比较
【1】.参数和适用对象不同
int.Parse的参数数据类型只能是string类型,适用对象为string类型的数据
convert.toInt参数比较多,具体可以参见最下面的重载列表
int.TryParse的参数只能是只能是string类型,适用对象为string类型的数据
【2】.异常情况不同
异常主要是针对数据为null或者为""的情况
Convert.ToInt32 参数为 null 时,返回 0;Convert.ToInt32 参数为 "" 时,抛出异常;int.Parse 参数为 null 时,抛出异常。; int.Parse 参数为 "" 时,抛出异常。int.TryParse()方法比int.Parse()方法多了一个异常处理,如果出现异常则返回false,并且将输出参数返回0。
【3】.返回值不同
int.TryParse与int.Parse和Convert.ToInt 在返回值的不同是返回bool类型。获取转换后的值是通过out result这个参数获取的。
4、使用AS操作符转换
使用AS操作符转换,但是AS只能用于引用类型和可为空的类型。使用as有很多好处,当无法进行类型转换时,会将对象赋值为NULL,避免类型转换时报错或是出异常。C#抛出异常在进行捕获异常并进行处理是很消耗资源的,如果只是将对象赋值为NULL的话是几乎不消耗资源的(消耗很小的资源)。
(未完待续)
5、装箱和拆箱
装箱和拆箱在值类型和引用类型之间架起了一座桥梁,使得任何 value-type 的值都可以转换为 object 类型的值,反过来转换也可以。
装箱:装箱是指将一个值类型的数据隐式地转换成一个对象类型(object)的数据。执行装箱操作时不可避免的要在堆上申请内存空间,并将堆栈上的值类型数据复制到申请的堆内存空间上,这肯定是要消耗内存和cpu资源的。注意:在执行装箱转换时,也可以使用显式转换。
int i = 0;
object obj = i; //装箱:值类型转换为引用类型
int j = (int)obj; //拆箱:引用类型转换为值类型
拆箱:拆箱是指将一个对象类型的数据显式地转换成一个值类型数据。拆箱过程是装箱的逆过程,是将存储在堆上的引用类型值转换为值类型并赋给值类型变量。拆箱操作分为两步:一是检查对象实例,确保它是给定值类型的一个装箱值;而是将该值从实例复制到值类型变量中。
装箱拆箱注意事项:
装箱操作可以隐式进行,但拆箱操作必须显示。
在装箱的时候,并不需要显示类型转换。但在拆箱时需要类型转换。
这是因为在拆箱时对象可以被转换为任何类型。
装什么拆什么
装箱就是要在托管堆重开辟空间,不但要装数值而且还要装类型
所以说装什么拆什么,也就是用什么值类型装箱,就要用什么值类型拆箱。
装箱和拆箱都是要消耗内存和cpu资源的,也就造成效率降低,所以要尽量避免使用。
装箱拆箱应用——定义方法
static void add(object i)
{
……
}
static void Main(string[] args)
{
short s = 10;
int i = 100;
long l = 1000;
add(s);
add(i);
add(l);
}
注:可以理解为我定义一个object类型,好多小类型可以赋值过来。