is仅做类型检查返回bool,as尝试转换并返回目标引用或null;两者IL均用isinst指令,但as多赋值操作;连续is+强转触发两次类型检查,应改用as判空或模式匹配。

is 和 as 在 IL 层面的本质区别
is 运算符只做类型检查,返回 bool;as 运算符尝试转换,成功返回目标引用,失败返回 null(对引用类型)或 default(T)(对可空值类型)。两者在 IL 中都调用 isinst 指令,但 as 多一步赋值操作——这步开销极小,几乎可忽略。
连续使用 is + 强制转换时性能更差
常见反模式:if (obj is string) { var s = (string)obj; ... }。这会触发两次类型检查:一次 is,一次强制转换中的隐式 isinst。JIT 通常不会优化掉第二次检查。
- 正确写法是直接用
as:var s = obj as string; if (s != null) { ... } - 对值类型(如
int?)需注意:as不支持非可空值类型,只能用于引用类型或可空值类型 - 如果后续必须用非空值类型,且已知安全,可用
obj as string ?? throw new InvalidOperationException(),避免重复检查
as 在热路径中略快,但差异通常不构成瓶颈
单次调用下,as 比 is + 强转快约 10%–15%(实测 .NET 6+ x64),因为省去一次运行时类型验证。但这个差距只有在每秒百万级类型判断时才可能被观测到。
- 真实业务代码中,类型检查往往不是热点,IO、内存分配、锁竞争才是瓶颈
- 过度纠结
isvsas的微秒级差异,不如检查是否误用了装箱(比如对int频繁is object) - 使用
as时务必判空,否则可能引入NullReferenceException,调试成本远高于那几纳秒
pattern matching(C# 7+)改变了权衡逻辑
现代 C# 推荐用模式匹配替代裸 is 或 as,例如 if (obj is string s) { /* s 已声明且非 null */ }。它在语义上等价于 as + 判空,但由编译器生成更紧凑的 IL,且变量作用域清晰。
- 这种写法既安全又高效,JIT 可对其做更好优化
- 对继承链深的对象,
is Type t和as Type性能表现一致,都依赖 CLR 的类型系统缓存 - 注意:模式匹配在结构体上会产生复制,若类型较大(如含数组字段),
as(仅适用引用类型)反而更轻量
实际编码中,优先选语义清晰的写法,而不是预设“哪个更快”。真正影响性能的,往往是类型检查发生的次数和上下文,而不是运算符本身。











