任务一 隐式转换
一、数据类型转换运算符
数据类型转换运算符用于强制转换数据类型。
核心用途: 主要用于数值类型之间的转换,特别是缩小转换,或已知兼容的引用类型向下转换。
语法
(目标类型)表达式
-
( ) 是强制转换运算符
-
目标类型:运算符的参数,指定要转换到的类型
-
(int) 表示"转换为int类型的操作"
-
(double) 表示"转换为double类型的操作
-
(string) 表示"转换为string类型的操作"
-
表达式:运算符的操作数,要被转换的值
特点:
-
编译时检查,运行时可能溢出
-
一元运算符:只需要一个操作数(在它右侧的值)
-
优先级较高:在表达式中优先于大多数算术运算符
-
右结合性:从右向左运算
用法概括
// 示例1:浮点数转整数(截断小数)
double price = 19.95;
int truncatedPrice = (int)price; // 结果为 19(直接丢弃小数部分)
// 示例2:大范围类型转小范围类型(可能溢出)
long bigNumber = 5000000000; // 50亿
int smallNumber = (int)bigNumber; // 结果为 705032704(溢出)
// 示例3:字符转整数(获取ASCII码)
char letter = 'A';
int asciiValue = (int)letter; // 结果为 65
// 示例4:枚举转整数
enum Status { Active = 1, Inactive = 0 }
int statusValue = (int)Status.Active; // 结果为 1
// 示例5:向下转换(需要类型兼容)
object obj = 42;
int numberFromObject = (int)obj; // 成功,因为obj实际是int
// 会失败的情况:
// string text = "123";
// int willFail = (int)text; // 编译错误:不能直接将string转换为int
(int)表达式
用途:用于强制把目标类型转换为整型
(int)整数|实数|字符|枚举|object
//场景1:大转小(截断小数 精度丢失)
double d = 5.7;
int i = (int)d; //5
//场景2:大转小(数据溢出)
uint large = 4000000000;
int signed = (int)large; // -294967296 (溢出)
//场景3:字符串转整型(编译时类型检测)
string text = "123";
int number = (int)text; // 编译错误:不能直接将string转换为int
//场景4:字符转整型(获取ASCII码)
char letter = 'A';
int ascii = (int)letter; // 65
// 场景5:枚举转整数
enum Status { Active = 1, Inactive = 0 }
int statusValue = (int)Status.Active; //1
//场景6:引用类型(拆箱)
object obj = 42;
int number = (int)obj; // 42
(char)表达式
用途:用于强制把目标类型(主要是数值类型)转换为字符型
int code1 = 65;
char letter1 = (char)code1; // 'A'
int code2 = 97;
char letter2 = (char)code2; // 'a'
//超出char范围的转换
int largeNumber = 100000;
char largeChar = (char)largeNumber; // 会截断,可能得到意外字符
// 整数转字符(ASCII码)
int asciiCode = 65;
char letter = (char)asciiCode; // 'A'
Console.WriteLine($"{asciiCode} -> '{letter}'");
// 另一个示例
int code = 97;
char lowercaseA = (char)code; // 'a'
Console.WriteLine($"{code} -> '{lowercaseA}'");
// 浮点数转字符(先截断为整数)
double pi = 3.14;
char charFromDouble = (char)pi; // ASCII 3 → 不可见字符
Console.WriteLine($"π {pi} -> 字符代码: {(int)charFromDouble}");
// 注意:超出char范围的转换
int largeNumber = 100000;
char largeChar = (char)largeNumber; // 会截断,可能得到意外字符
Console.WriteLine($"{largeNumber} -> '{(int)largeChar}'");
(string)表达式(特殊)
用途:用于强制把目标类型转换为字符串型
注意:(string)实际上不能用于大多数类型到字符串的转换!这是一个常见的误解。
object obj = "hello";
string str = (string)obj;
Console.WriteLine(str);//"hello"
// 这是错误的用法(会编译错误):
// int number = 42;
// string text = (string)number; // 编译错误!
// 正确的字符串转换应该使用:
int number = 42;
string text1 = number.ToString(); // "42"
string text2 = Convert.ToString(123); // "123"
string text3 = $"{456}"; // "456"
// (string)只能用于原本就是string类型或继承关系的对象
object obj = "Hello";
string str = (string)obj; // 正确,因为obj实际是string
// 或者用于自定义的显式转换运算符
(double)表达式
用途:用于强制把目标类型转换为字符串型
// decimal → double(可能精度丢失)
decimal preciseValue = 123.4567890123456789m;
double approxValue = (double)preciseValue;
Console.WriteLine($"decimal: {preciseValue} -> double: {approxValue}");
// float → double(安全,但显式)
float floatValue = 3.14f;
double doubleValue = (double)floatValue; // 实际上可以隐式,但显式更明确
Console.WriteLine($"float: {floatValue} -> double: {doubleValue}");
// int → double(可以隐式,但显式也可用)
int wholeNumber = 42;
double asDouble = (double)wholeNumber; // 42.0
Console.WriteLine($"int: {wholeNumber} -> double: {asDouble}");
// 注意:从大范围到小范围
double bigDouble = 1.7E+308;
// float smallFloat = (float)bigDouble; // 可能溢出或精度严重丢失
(float)表达式
用途:用于强制把目标类型转换为字符串型
double d = 3.14;
float f = (float)d;
Console.WriteLine(f.GetType()); // System.Single
double precise = 3.14159265358979;
float approximate = (float)precise; // 精度丢失
decimal money = 999.99m;
float moneyFloat = (float)money; // 999.99f
(decimal)表达式
用途:用于强制把目标类型转换为decimal型
double d = 3.14;
decimal m = (decimal)d;
Console.WriteLine(m.GetType()); // System.Single
double d = 123.456;
decimal preciseDecimal = (decimal)d; // 123.456m
float f = 78.9f;
decimal fromFloat = (decimal)f; // 78.9m
(long)表达式
用途:用于强制把目标类型转换为long型
double d = 3.14;
long l = (long)d;
Console.WriteLine(l.GetType()); // System.Single
ulong bigUnsigned = 18446744073709551615; // ulong.MaxValue
long signedLong = (long)bigUnsigned; // -1(溢出)
Console.WriteLine($"ulong: {bigUnsigned} -> long: {signedLong}");
double withFraction = 987654321.99;
long wholePart = (long)withFraction; // 987654321(截断)
(byte)表达式
用途:用于强制把目标类型转换为字节整型
double d = 3.14;
byte b = (byte)d;
Console.WriteLine(b.GetType()); // System.Single
int largeNumber = 300;
byte smallByte = (byte)largeNumber; // 300 % 256 = 44
short mediumNumber = 128;
byte byteValue = (byte)mediumNumber; // 128
二、Parse方法
int.Parse()
核心用途: 专门用于字符串到数值的转换,要求输入必须是严格格式化的数字字符串。
特点
- 仅用于字符串,严格格式
用法概括
Console.WriteLine();
Console.WriteLine((int)3.14);//3
Console.WriteLine(int.Parse("3"));//3
Console.WriteLine(int.Parse("-3"));//-3
// Console.WriteLine(int.Parse("3.14"));//Unhandled exception
// Console.WriteLine(.Parse("3.14"));//Unhandled exception
// 示例1:标准数字字符串
string validNumber = "123";
int parsedNumber = int.Parse(validNumber); // 成功:123
// 示例2:带空格的字符串(会自动处理前后空格)
string spacedNumber = " 456 ";
int parsedSpaced = int.Parse(spacedNumber); // 成功:456
// 示例3:会抛出异常的情况
try
{
string nullString = null;
int result1 = int.Parse(nullString); // ArgumentNullException
string invalidString = "123abc";
int result2 = int.Parse(invalidString); // FormatException
string tooBig = "9999999999";
int result3 = int.Parse(tooBig); // OverflowException
}
catch (Exception ex)
{
Console.WriteLine($"Parse失败: {ex.GetType().Name}");
}
三、Convert方法
特点
- 运行时检查,处理null值
Convert.ToInt32() 方法
核心用途: 最通用的转换方法,可以处理多种输入类型,对null有默认处理。
用法概括
// 示例1:处理字符串(类似Parse)
string numberStr = "789";
int convertedNumber = Convert.ToInt32(numberStr); // 成功:789
// 示例2:处理null值(返回0)
string nullString = null;
int fromNull = Convert.ToInt32(nullString); // 结果为 0
// 示例3:处理其他基础类型
double d = 88.7;
int fromDouble = Convert.ToInt32(d); // 结果为 89(四舍五入)
bool flag = true;
int fromBool = Convert.ToInt32(flag); // 结果为 1
// 示例4:处理DBNull(数据库场景)
object dbNull = DBNull.Value;
int fromDbNull = Convert.ToInt32(dbNull); // 结果为 0
// 示例5:仍然会抛出异常的情况
try
{
string invalid = "abc123";
int result1 = Convert.ToInt32(invalid); // FormatException
decimal hugeValue = decimal.MaxValue;
int result2 = Convert.ToInt32(hugeValue); // OverflowException
}
catch (Exception ex)
{
Console.WriteLine($"Convert失败: {ex.GetType().Name}");
}
重要注意事项
(string)不能用于数值转字符串* - 使.ToString()Convert.ToString()
转换可能丢失数据 - 特别是大范围到小范围的转换
引用类型转换可能失败 - 使as运算符进行安全转换
自定义转换需要显式定义 - 通explicit operator关键字
考虑使用TryParse模式 - 对于可能失败的转换更安全
任务一 隐式转换
类型转换发生在赋值或操作数类型不同时。 常见的数据类型转换包括:
- 整数 → 浮点数
- 浮点数 → 整数
- 不同大小的整数之间转换
转换方式主要有:
- 隐式转换(Implicit Conversion):就是指编译器自动转换类型。当转换不会丢失数据时,编译器会自动进行隐式转换。不需要特殊语法,不会丢失数据。
- 显式转换(Explicit Conversion):就是指强制转换(强制转换运算符)类型。当转换可能丢失数据时,必须使用显式转换,否则编译器会报错。
隐式转换(自动转换)
1. 数值类型的隐式转换
遵循原则:从小类型向大类型转换。
byte → short → int → long → float → double
char → int → long → float → double
示例:
int i = 123;
long l = i; // 隐式转换 int → long
float f = l; // 隐式转换 long → float
示例:(整数 → 浮点数)
//整数可以安全转换为 `float`、`double` 或 `decimal`,因为浮点数的范围更大。
int numInt = 100;
float numFloat = numInt; // 隐式转换 int → float
double numDouble = numInt; // 隐式转换 int → double
decimal numDecimal = numInt; // 隐式转换 int → decimal
示例:(小范围整数 → 大范围整数)
//`byte` → `short` → `int` → `long`
byte smallNum = 200;
int bigNum = smallNum; // byte → int(无数据丢失)
显式转换
1. 强制类型转换
(1) 浮点数 → 整数
-
浮点数转换为整数时,小数部分会被截断(不四舍五入)。
-
如果浮点数超出目标整数范围,结果会溢出(可能变成负数或错误值)。
-
语法:
(目标类型)变量或值 -
示例:
double pi = 3.14159;int intPi = (int)pi; // 显式转换 double → int,intPi = 3(小数部分丢失)float bigFloat = 1.5e10f; // 15,000,000,000(超出 int 范围)int badConversion = (int)bigFloat; // 溢出,结果不可预测!double d = 123.456;int i = (int)d; // i = 123,小数部分丢失
(2) 大范围整数 → 小范围整数
-
如果大整数超出小类型的范围,数据会被截断(高位丢失)。
-
示例:
int bigNum = 300;byte smallByte = (byte)bigNum; // 300 > 255,溢出!smallByte = 44(300 - 256)
2.使用 Convert 类
System.Convert 类提供了一系列通用显式转换工具:
Convert 方法特点:
- 提供了一整套静态方法(如 ToInt32()、ToDouble())。
- 支持多种类型间的转换(如字符串、浮点数、日期等)。
- 对 null 的处理:
- 输入为 null 时:
- 转换为数值类型 → 返回 0。
- 转换为字符串 → 返回 null。
- 会进行四舍五入(如 Convert.ToInt32(3.6) → 4)。
- 转换失败时抛出异常(如 FormatException、OverflowException)。
示例
int i = Convert.ToInt32("123"); // 字符串转int
double d = Convert.ToDouble("123.45"); // 字符串转double
string s = Convert.ToString(123); // int转字符串
| 方法 | 说明 |
|---|---|
Convert.ToInt32() | 转换为 int(四舍五入) |
Convert.ToInt64() | 转换为 long |
Convert.ToSingle() | 转换为 float |
Convert.ToDouble() | 转换为 double |
Convert.ToDecimal() | 转换为 decimal |
3. Parse 方法
Parse 方法用于:字符串→目标类型的显式转换
特点
- 专用于字符串到其他类型的转换(如 int.Parse("123"))。
- 对于数值类型,支持格式字符串
- 对格式要求严格:
- 必须完全符合目标类型格式。
- 不支持自动四舍五入(如 int.Parse("3.9") 直接抛异常)。
- 转换失败时抛出 FormatException 或 OverflowException。
示例
int i = int.Parse("123");
double d = double.Parse("123.45");
string str = "123";
int num = int.Parse(str); // 显式转换,可能抛异常
// 以下会抛异常:
int invalid1 = int.Parse("3.14"); // FormatException(不是整数)
int invalid2 = int.Parse("9999999999"); // OverflowException(超出int范围)
2. TryParse 方法
TryParse: 安全的格式转换
特点
- 与 Parse 功能相同,但不抛异常,而是返回 bool 表示是否成功。
- 通过 out 参数返回转换结果。
- 适合用户输入或不可信数据源。
示例
bool success = int.TryParse("123", out int result);
if(success) {
// 使用result
}
string input = "123";
bool success = int.TryParse(input, out int result);
if (success) {
Console.WriteLine(result); // 转换成功
} else {
Console.WriteLine("输入无效");
}
转换方法对比
| 转换方式 | 是否需要显式声明 | 是否可能丢失数据 | 失败时行为 |
|---|---|---|---|
| 隐式转换 | 否 | 否 | 编译错误 |
| 显式转换 | 是 | 可能 | 运行时异常 |
| Convert | 是 | 可能 | 抛出异常 |
| Parse | 是 | 可能 | 抛出异常 |
| TryParse | 是 | 可能 | 返回false |
对比总结
| 特性 | 强制转换 (int)x | Convert 类 | Parse | TryParse |
|---|---|---|---|---|
| 输入类型 | 数值/兼容类型 | 任意类型 | 仅字符串 | 仅字符串 |
null 处理 | 编译错误 | 返回 0 或 null | 抛异常 | 返回 false |
| 四舍五入 | 截断小数 | 支持 | 不支持 | 不支持 |
| 失败行为 | 可能溢出 | 抛异常 | 抛异常 | 返回 false |
| 性能 | 最快 | 中等 | 中等 | 最安全 |
常见转换问题
(1) 浮点数 → 整数(截断 vs 四舍五入)
double num = 3.9;
int truncated = (int)num; // 3(截断)
int rounded = Convert.ToInt32(num); // 4(四舍五入)
(2) decimal 必须显式转换
decimal 不能隐式转换到 float/double,必须强制转换:
decimal money = 100.50m;
double approx = (double)money; // 必须显式转换
(3) 字符串 → 数值
string input = "123";
int num = int.Parse(input); // 方法1:Parse(失败抛异常)
int num2 = Convert.ToInt32(input); // 方法2:Convert(推荐)
bool success = int.TryParse(input, out int num3); // 方法3:安全转换
总结
| 转换场景 | 推荐方式 |
|---|---|
| 整数 → 浮点数 | 隐式转换(自动) |
| 浮点数 → 整数 | (int) 或 Convert.ToInt32 |
| 大整数 → 小整数 | (byte) 或 checked 检查 |
| 字符串 → 数值 | int.Parse 或 TryParse |
转换方法
| 转换类型 | 方法 | 示例 |
|---|---|---|
| 隐式转换(整数→浮点) | 自动转换 | double d = 100; |
| 显式转换(浮点→整数) | (int) 强制转换 | int i = (int)3.14; |
| 四舍五入 | Convert.ToInt32 | Convert.ToInt32(3.6); → 4 |
| 安全转换 | TryParse | int.TryParse("123", out num); |
| 溢出检查 | checked | checked { int x = a + b; } |
练习(数据类型转换20道)
1. 隐式转换 int → double
int num = 100;
double result = num; // 隐式转换
Console.WriteLine(result);
问题:输出结果是什么?
2. 隐式转换 long → decimal
long bigNum = 9_223_372_036_854_775_807;
decimal result = bigNum;
Console.WriteLine(result);
问题:能否编译?为什么?
3. 隐式转换 byte → float
byte smallNum = 255;
float result = smallNum;
Console.WriteLine(result);
问题:输出结果是什么?
4. 混合运算(int + double)
int a = 10;
double b = 3.5;
double result = a + b; // 哪个类型被隐式转换?
Console.WriteLine(result);
问题:a 会被转换为什么类型?
5. 隐式转换 short → double
short num = 32_767;
double result = num;
Console.WriteLine(result);
问题:输出结果是什么?
6. 显式转换 double → int(截断)
double pi = 3.14159;
int intPi = (int)pi; // 显式转换
Console.WriteLine(intPi);
问题:输出结果是什么?
7. 显式转换 float → int(溢出风险)
float bigNum = 1.5e10f; // 15,000,000,000
int result = (int)bigNum;
Console.WriteLine(result);
问题:会发生什么?
8. 显式转换 decimal → int
decimal money = 123.99m;
int result = (int)money;
Console.WriteLine(result);
问题:输出结果是什么?
9. 显式转换 double → byte
double num = 300.75;
byte result = (byte)num;
Console.WriteLine(result);
问题:输出结果是什么?
10. 显式转换 float → long
float num = 9.9f;
long result = (long)num;
Console.WriteLine(result);
问题:输出结果是什么?
11. Convert.ToInt32(四舍五入)
double num = 3.6;
int result = Convert.ToInt32(num);
Console.WriteLine(result);
问题:输出结果是什么?
12. Convert.ToInt32 对负数的作用
double num = -2.4;
int result = Convert.ToInt32(num);
Console.WriteLine(result);
问题:输出结果是什么?
13. Convert.ToInt64(double → long)
double bigNum = 1.5e19;
long result = Convert.ToInt64(bigNum);
Console.WriteLine(result);
问题:能否正常运行?
14. Convert.ToDecimal(float → decimal)
float num = 3.14f;
decimal result = Convert.ToDecimal(num);
Console.WriteLine(result);
问题:输出结果是什么?
15. Convert.ToByte(double → byte)
double num = 255.9;
byte result = Convert.ToByte(num);
Console.WriteLine(result);
问题:输出结果是什么?
16. int.Parse(字符串 → int)
string input = "123";
int result = int.Parse(input);
Console.WriteLine(result);
问题:如果 input = "abc",会发生什么?
17. double.TryParse(安全转换)
string input = "3.14";
bool success = double.TryParse(input, out double result);
Console.WriteLine(success ? result : "转换失败");
问题:如果 input = "3.14x",输出是什么?
18. decimal.Parse(高精度转换)
string input = "99.99";
decimal result = decimal.Parse(input);
Console.WriteLine(result);
问题:如果 input = "1e10",能否转换?
19. int.TryParse 处理用户输入
Console.Write("请输入一个整数:");
string input = Console.ReadLine();
if (int.TryParse(input, out int num)) {
Console.WriteLine($"你输入的是:{num}");
} else {
Console.WriteLine("输入无效!");
}
问题:如果用户输入 "12.3",输出是什么?
20. checked 检查溢出
int a = int.MaxValue;
int b = 2;
checked {
int result = a + b; // 会发生什么?
Console.WriteLine(result);
}
问题:能否正常运行?
答案(数据类型转换20道)
1. 问题:输出结果是什么?
✅ 答案:100.0(int 自动转为 double)
2. 问题:能否编译?为什么?
✅ 答案:可以,long 可以隐式转为 decimal。
3. 问题:输出结果是什么?
✅ 答案:255.0(byte 可以隐式转为 float)
4.问题:a 会被转换为什么类型?
✅ 答案:a 隐式转为 double,输出 13.5。
5. 问题:输出结果是什么?
✅ 答案:32767.0(short 可以隐式转为 double)
6. 问题:输出结果是什么?
✅ 答案:3(小数部分被丢弃)
7.问题:会发生什么?
✅ 答案:溢出,结果不可预测(int 最大值约 2.1e9)。
8. 问题:输出结果是什么?
✅ 答案:123(小数部分被截断)
9.问题:输出结果是什么?
✅ 答案:44(300 - 256 = 44,溢出截断)
10. 问题:输出结果是什么?
✅ 答案:9(小数部分被丢弃)
11. 问题:输出结果是什么?
✅ 答案:4(四舍五入)
12. 问题:输出结果是什么?
✅ 答案:-2(向零舍入)
13. 问题:能否正常运行?
✅ 答案:如果超出 long 范围,抛出 OverflowException。
14. 问题:输出结果是什么?
✅ 答案:3.14(精确转换)
15. 问题:输出结果是什么?
✅ 答案:255(小数部分四舍五入,但不超过 byte 最大值)
16. 问题:如果 input = "abc",会发生什么?
✅ 答案:抛出 FormatException。
17. 问题:如果 input = "3.14x",输出是什么?
✅ 答案:"转换失败"(TryParse 不会抛异常)
18.问题:如果 input = "1e10",能否转换?
✅ 答案:不能,decimal.Parse 不支持科学计数法。
19. 问题:如果用户输入 "12.3",输出是什么?
✅ 答案:"输入无效!"(int.TryParse 不接受小数)
20. 问题:能否正常运行?
✅ 答案:抛出 OverflowException(checked 检测到溢出)