C#强制类型转换(显示转换)和安全类型转换

发布于:2025-09-05 ⋅ 阅读:(17) ⋅ 点赞:(0)

目录

强制类型转换(显式转换)

1.核心特性

2. 适用场景

2.1.值类型之间的兼容转换

2.2.引用类型的“继承链转换”

2.3.object与其他类型的转换

安全类型转换

1.as关键字:尝试转换,失败返回null

1.1.核心特性

1.2.适用场景

1.2.1.引用类型的安全转换

1.2.2.可空值类型的安全转换

2. is 关键字:先判断兼容性,再转换

2.1.核心特性

2.2.适用场景

2.2.1.值类型的安全转换

2.2.2.引用类型的安全转换(替代as)

2.2.3.复杂类型的多分支判断

强制转换 vs 安全转换

什么时候用哪种转换?

常见错误与避坑


       本篇文章来分享一下C#的强制类型转换和安全类型转换,强制类型转换也称为显示转换。在C#中,类型转换是将一种数据类型的值转换为另一种数据类型的操作,核心分为强制类型转换(显式转换)和安全类型转换(as关键字、is关键字)两类。

强制类型转换(显式转换)

       强制类型转换是开发者确认两种类型可兼容的转换方式。它直接对值进行类型转换,若转换不合法会立即抛出异常。

1.核心特性

(1)语法:目标类型 变量名 = (目标类型)源值;

(2)转换逻辑:直接操作内存中数据的类型标识(或值的格式),要求两种类型在编译期/运行期具备“可转换关系”(如继承、值类型兼容)。

(3)错误处理:若转换不合法(如将string转int、将父类实例转子类),立即抛出InvalidCastException异常,中断程序执行(未捕获时)。

(4)适用范围:支持值类型(如int→long)和引用类型(如object→string、子类→父类)。

2. 适用场景

       强制转换并非“任意类型都能转”,仅支持以下合法场景:

2.1.值类型之间的兼容转换

       当两种值类型具备“范围包含”或“格式兼容”关系时,可强制转换,可能丢失精度

(1)范围窄→范围宽(隐式转换也支持,强制转换可显式声明):

       如 int(4 字节)→long(8 字节)、float→double,转换安全无精度丢失。

int num1 = 100;
long num2 = (long)num1;//合法,也可省略 (long) ,隐式转换

(2)范围宽→范围窄(必须强制转换,可能丢失精度):

       如long→int、double→float,若源值超出目标类型范围,会导致“溢出”(默认不抛异常,仅返回错误值;开启溢出检查后抛OverflowException)。

long bigNum = 2147483648;//超出 int 最大值(2^31 - 1=2147483647)
int smallNum = (int)bigNum;//溢出,smallNum 结果为2147483648 - 2^32 = -2147483648,错误值

2.2.引用类型的“继承链转换”

       父类实例→子类实例,必须强制转换,且运行期需确保父类实例本质是子类对象,父类引用可指向子类对象(多态),但需强制转换才能调用子类特有成员。

public class Animal { }
public class Dog : Animal
{
    public void Bark()
    {
        Debug.Log("小狗汪汪~");
    }
}
public class Test : MonoBehaviour
{
    public void Start()
    {
        Animal animal = new Dog();//多态:父类引用指向子类对象
        Dog dog = (Dog)animal;//合法:强制转换后可调用 Bark()
        dog.Bark();//执行成功
    }
}

       若父类实例不是子类对象,强制转换会抛 InvalidCastException:

Animal animal = new Animal();//父类实例
Dog dog = (Dog)animal;//运行期抛异常:无法将 Animal 转换为 Dog

2.3.object与其他类型的转换

       object是所有类型的基类,其他类型与object之间可强制转换。

其他类型与object之间的转换包括装箱和拆箱:

1.装箱:值类型→object,支持隐式转换,也可强制转换。

2.拆箱:object→值类型,必须强制转换,且object中存储的必须是目标值类型(否则抛 InvalidCastException)。

//装箱:int→object
int num = 10;
object obj = (object)num;//合法,也可省略 (object) 隐式装箱

//拆箱:object→int(必须强制转换)
int num2 = (int)obj;//合法,obj 中存储的是 int

//错误拆箱:obj 中存储的是 int,转 string 抛异常
string str = (string)obj;//运行期抛异常:无法将 int 转换为 string

安全类型转换

       安全类型转换是开发者不确定类型是否兼容,希望避免异常的转换方式,依赖as关键字(直接转换)和is关键字(先判断再转换)。

1.as关键字:尝试转换,失败返回null

1.1.核心特性

(1)语法:目标类型 变量名 = 源值 as 目标类型;

(2)转换逻辑:尝试将源值转换为目标类型,若兼容则返回转换后的值;若不兼容则返回null(不抛异常)。

(3)关键限制:仅支持引用类型(如class、interface、string)和可空值类型(如int?、double?);不支持非可空值类型(如 int、float),若用于非可空值类型会编译报错。

(4)错误处理:转换失败时返回null,需通过if(变量名 == null) 判断结果。

1.2.适用场景

1.2.1.引用类型的安全转换

       替代 “可能失败的强制转换”,避免异常:

public class Animal { }
public class Dog : Animal 
{ 
    public void Bark() 
    { 
        Debug.Log("小狗汪汪~");
    } 
}
public class Cat : Animal 
{ 
    public void Meow() 
    {
        Debug.Log("小猫喵喵~");
    } 
}
public class Test : MonoBehaviour
{
    public void Start()
    {
        Animal animal = new Dog();//父类引用指向 Dog 实例

        //用 as 转换为 Dog(兼容,返回 Dog 实例)
        Dog dog = animal as Dog;
        if (dog != null)
        {
            dog.Bark();//执行成功
        }

        //用 as 转换为 Cat(不兼容,返回 null)
        Cat cat = animal as Cat;
        if (cat != null)
        {
            cat.Meow();//条件不满足,不执行
        }
    }
}

1.2.2.可空值类型的安全转换

       非可空值类型需先包装为可空值类型,才能用 as 转换:

object obj = 10;//obj中存储的是 int

//错误:非可空值类型 int 不能用 as 转换(编译报错)
//int num = obj as int;

//正确:用可空值类型 int? 转换
int? num = obj as int?;
if (num != null)
{
    Console.WriteLine(num); //输出:10
}

//转换失败:obj 中是 int,转 double? 返回 null
double? dNum = obj as double?;
if (dNum == null)
{
    Console.WriteLine("转换失败");//输出:转换失败
}

2. is 关键字:先判断兼容性,再转换

       is 关键字本身不执行转换,仅判断源值是否兼容于目标类型,返回bool值(true/false)。通常与模式匹配结合,实现“判断 + 转换”一步完成,比as更直观。

2.1.核心特性

(1)语法

基础判断:bool 兼容 = 源值 is 目标类型;

模式匹配(判断 + 转换):if (源值 is 目标类型 变量名)

(2)转换逻辑:先判断源值是否兼容于目标类型(运行期检查);若兼容,自动将源值转换为目标类型并赋值给变量(无需额外强制转换);若不兼容,不执行后续逻辑(不抛异常)。

(3)适用范围:支持所有类型(值类型、引用类型、可空值类型),无as的类型限制。

2.2.适用场景

2.2.1.值类型的安全转换

       as不支持非可空值类型,is可完美解决:

object obj = 100;
//用 is 判断并转换为 int(非可空值类型)
if (obj is int num)
{
    Console.WriteLine(num + 50);//输出:150(转换成功,直接使用num)
}

//用 is 判断并转换为 double(不兼容,不执行)
if (obj is double dNum)
{
    Console.WriteLine(dNum);//不执行
}

2.2.2.引用类型的安全转换(替代as)

       相比as,is模式匹配无需手动判断null,代码更简洁:

Animal animal = new Cat();

//用 is 模式匹配:判断是否为 Cat,若是则自动转换为 cat 变量
if (animal is Cat cat)
{
    cat.Meow();//执行成功
}

//用 is 模式匹配:判断是否为 Dog,若不是则不执行
if (animal is Dog dog)
{
    dog.Bark();//不执行
}

2.2.3.复杂类型的多分支判断

       在多类型分支场景中,is模式匹配比as更易读:

public class Animal { }
public class Dog : Animal 
{ 
    public void Bark() 
    { 
        Debug.Log("小狗汪汪~");
    } 
}
public class Cat : Animal 
{ 
    public void Meow() 
    {
        Debug.Log("小猫喵喵~");
    } 
}
public class Bird : Animal
{
    public void Sing()
    {
        Debug.Log("小鸟吱吱~");
    }
}
public class Test : MonoBehaviour
{
    public void Start()
    {
        AnimalSound(new Dog());//Bark 执行
        AnimalSound(new Bird());//Sing 执行
    }
    private void AnimalSound(Animal animal)
    {
        if (animal is Dog dog)
        {
            dog.Bark();
        }
        else if (animal is Cat cat)
        {
            cat.Meow();
        }
        else if (animal is Bird bird)
        {
            bird.Sing();
        }
        else
        {
            Console.WriteLine("未知动物");
        }
    }
}

强制转换 vs 安全转换

维度

强制类型转换 (T)obj

安全类型转换(as/is)

语法

(目标类型)源值

as:源值 as 目标类型

is:源值 is 目标类型 变量

错误处理

不兼容时抛InvalidCastException

as:返回 null

is:不执行逻辑(均不抛异常)

支持类型

所有类型(值类型、引用类型)

as:引用类型/可空值类型;

is:所有类型

适用场景

确定类型兼容,需即时暴露错误

不确定类型兼容,需避免异常

性能

无额外开销(直接转换)

as:无额外开销

is:仅多一次类型判断(可忽略)

代码健壮性

低(异常可能中断程序)

高(容错性强,错误可显式处理)

什么时候用哪种转换?

1.优先用is模式匹配

场景:不确定类型兼容、需要多分支判断、转换值类型时;

理由:代码简洁、无异常风险、支持所有类型。

2.其次用as关键字

场景:仅需单次引用类型转换,且需用null判断结果时;

理由:比is少一次类型判断(理论性能略优),但需手动处理null。

3.最后用强制转换 (T)

场景:100%确定类型兼容(如单例模式中反射获取的实例、父类引用明确指向子类对象);

理由:无额外开销,且能即时暴露错误(若代码逻辑出错,强制转换抛异常便于调试);

禁忌:避免在可能不兼容的场景中使用(如用户输入、动态数据转换),否则易引发未捕获异常。

常见错误与避坑

1.非可空值类型用 as 转换:编译报错,需改用 is 或强制转换。

//错误:int 是非可空值类型,不能用 as
int num = obj as int;

//正确:用 is 模式匹配
if (obj is int num) { }

2.强制转换父类实例为子类:若父类实例不是子类对象,运行期抛异常,需先判断(用is)。

Animal animal = new Animal();
//错误:animal 不是 Dog 实例,强制转换抛异常
Dog dog = (Dog)animal;

//正确:先判断再转换
if (animal is Dog dog) { }

3.as转换后不判断null:直接使用可能抛NullReferenceException,需先检查null。

Dog dog = animal as Dog;
//错误:若 dog 是 null,调用 Bark() 抛空引用异常
dog.Bark();

//正确:先判断 null
if (dog != null) 
{ 
    dog.Bark(); 
}

       好了,本次的分享到这里就结束啦,希望对你有所帮助~


网站公告

今日签到

点亮在社区的每一天
去签到