c# is 和 as 操作符的区别

来源:这里教程网 时间:2026-02-21 17:36:54 作者:

is 操作符只判断类型,不转换

is
用于运行时检查对象是否属于某个类型(或其派生类型),返回
true
false
,**不会执行任何类型转换**。它不抛异常,也不改变原变量值。

常见错误是以为

is
后能直接用转型结果:

if (obj is string) {
    Console.WriteLine(obj.Length); // 编译错误!obj 还是 object 类型
}

正确写法必须显式转换(或用模式匹配):

老写法:
if (obj is string) { string s = (string)obj; ... }
C# 7+ 推荐:
if (obj is string s) { Console.WriteLine(s.Length); }
—— 这里
s
是新声明的局部变量,不是
obj
被“改类型”了

as 操作符尝试转换,失败返回 null

as
尝试将对象引用转换为指定引用类型或可空类型。**仅适用于引用类型和可空值类型**;对非可空值类型(如
int
DateTime
)使用会编译报错。

它不抛异常,转换失败时返回

null
(对可空值类型返回
null
值)。但要注意:如果目标类型是
string
object
等引用类型,源为
null
时也返回
null
,无法区分“本来就是 null”和“转换失败”。

合法:
var s = obj as string;
obj
object
非法:
var i = obj as int;
→ 编译错误,
int
是非可空值类型
合法(可空):
var i = obj as int?;

is 和 as 组合使用容易引发两次类型检查

这是性能和可读性上最常被忽略的问题。下面这段代码效率低且冗余:

if (obj is string) {
    string s = obj as string; // 又做了一次运行时类型检查
    Process(s);
}

CLR 在

is
as
中都会执行相同的类型判定逻辑,相当于重复工作。C# 7+ 的模式匹配语法正是为解决这个而生:

✅ 推荐:
if (obj is string s) Process(s);
—— 一次检查,一次赋值
✅ 或者直接用
as
+ 空检查:
string s = obj as string; if (s != null) Process(s);
❌ 避免
is
后紧跟
as
,除非你明确需要中间的布尔判断逻辑

值类型场景下 as 完全不可用,is 仍可用

对值类型(如

int
Guid
、自定义
struct
),
as
不能用,编译器直接拒绝。但
is
可以配合装箱/拆箱判断:

object obj = 42;
if (obj is int) { /* true */ }
// var x = obj as int; // 编译错误

若要安全获取值类型,只能用

is
+ 显式拆箱,或用泛型方法(如
Convert.ChangeType
);注意拆箱必须类型完全一致,
obj is int
成立不代表
(int)obj
一定成功(比如
obj
long
装箱的 42,
is int
false
,但有人误以为可以强转)。

真正容易被忽略的是:

is
对值类型的判断本质是“是否为该类型装箱后的对象”,它不支持隐式转换检查(比如
long
int
),这点和
as
的适用范围限制一起,让值类型的安全转换始终比引用类型更繁琐。

相关推荐