在c#中,as、is和强制转换不可互换:as用于安全向下转型(返回null而非异常),is用于类型检查(推荐配合模式匹配避免竞态),强制转换易抛nullreferenceexception或invalidcastexception;装箱值类型只能拆箱回原类型,跨数值转换须用convert类。

直接说结论:在 C# 中,as、is 和强制转换((Type)expr)不是可互换的替代品;选错会引发 InvalidCastException、返回 null 或静默失败,尤其在处理继承链、泛型、接口或 null 值时。
什么时候该用 as 而不是强制转换
as 只适用于引用类型和可空值类型,且只做“安全向下转型”——即运行时类型兼容但不确定是否为该具体类型时使用。它失败时不抛异常,而是返回 null(对可空值类型是 null,对不可空值类型编译不通过)。
- 必须确保目标类型是引用类型(如
string、IEnumerable<t></t>)或可空值类型(如int?),否则编译报错 - 如果表达式结果为
null,as也返回null,不会抛异常——这和强制转换完全不同 - 常见误用:对
int到long这类数值转换写obj as long→ 编译失败,因为long是非空值类型 - 正确示例:
var list = obj as IList<string>; if (list != null) { ... }</string>
is 检查后还用不用再 cast
is 只判断兼容性,不执行转换。传统写法是先 if (obj is SomeType) 再 (SomeType)obj,但这有两次类型检查开销,且在多线程下存在竞态风险(对象可能在检查后、转换前被修改)。
- C# 7.0+ 推荐用模式匹配语法一步到位:
if (obj is SomeType st) { /* st 已是转换后的变量 */ } - 注意:
is对值类型(如int)也会装箱一次,若频繁调用需留意性能 - 对泛型类型参数,
is T在运行时受限于类型擦除,某些情况下无法准确判断(如T是未约束泛型参数)
强制转换 (Type)expr 的三个高危场景
强制转换语法最简,但最容易在运行时崩。它不检查 null,不区分装箱/拆箱路径,也不处理用户定义转换的隐式/显式标记。
- 对 null 引用强制转引用类型 → 立刻抛
NullReferenceException(不是InvalidCastException) - 对已装箱的
int强制转long→ 抛InvalidCastException,因为装箱类型必须精确匹配,不能跨数值类型转换 - 调用
(MyStruct)obj时,若obj是装箱的int,即使MyStruct有从int的显式转换操作符,也不会触发——装箱对象只能拆箱回原类型 - 安全做法:先用
is或as排查,再 cast;或改用Convert.ChangeType处理跨类型数值转换
容易被忽略的边界点:装箱、泛型和自定义转换
很多问题不是出在语法上,而是出在类型系统底层行为里。比如你写了 int i = 42; object o = i; long l = (long)o;,这段代码看着合理,实际必崩。
- 装箱后的值类型只能拆箱回原始类型,
(long)(object)42是非法的,哪怕long能无损表示int - 自定义
implicit/explicit转换操作符只在编译期起作用,对运行时对象(如object变量)无效 - 泛型方法中
T t = (T)baseObj;如果T是值类型,而baseObj是装箱的其他类型,同样会崩溃 - 真正需要跨类型数值转换时,应走
Convert.ToInt64(obj)或Convert.ChangeType(obj, typeof(long)),它们内部做了类型路由











