is 用于判断类型兼容性(可安全转换),返回 bool 且不抛异常;as 执行安全转换,失败返回 null,仅适用于引用类型和可空值类型。

is 运算符用来判断类型兼容性,不是类型相等
is 检查对象是否与指定类型**兼容**(即能否安全转换),不抛异常,返回 bool。常见误区是以为它在做“精确类型匹配”——其实 obj is string 对 string 子类(虽无)或装箱的 string 都返回 true,但对 null 也返回 false(除非类型是可空引用类型且启用了 nullable context)。
实际用法中,推荐搭配模式匹配简化逻辑:
if (obj is string s) {
Console.WriteLine($"长度:{s.Length}");
}
这比先 is 再强制转换更安全、更简洁。注意:is 不会触发用户定义的转换运算符,只走运行时类型检查路径。
- 不能用于泛型类型参数未约束时的直接判断(如
T is IDisposable编译失败,需用typeof(T).IsAssignableFrom(typeof(IDisposable))或T? : IDisposable约束) - 在值类型上使用
is可能引发装箱(如int i = 5; bool b = i is object;),高频场景下建议避免 - .NET 7+ 支持
is检查const模式,例如obj is 42或obj is "hello"
as 运算符执行安全转换,失败返回 null 而非抛异常
as 仅适用于引用类型和可空值类型,尝试将对象转换为指定类型,成功则返回目标类型实例,失败返回 null(对可空值类型返回 null,对不可空值类型编译不通过)。
典型误用是跟 is 连续使用:
if (obj is TextBox) {
var tb = obj as TextBox; // 多余!已知是 TextBox,直接 (TextBox)obj 更高效
}
正确做法是二选一:要么用 as + 空检查,要么用模式匹配 is 带声明。两者语义等价,但 as 在需要多次使用转换结果时更清晰:
var button = sender as Button;
if (button != null) {
button.Enabled = false;
button.Text = "Processing...";
}
-
as不支持用户自定义转换操作符,也不支持隐式/显式转换定义 - 对非引用类型(如
int)使用as会编译错误;想转int?可以,但obj as int不合法 - IL 层面,
as编译为isinst指令,比castclass(强制转换)少一次类型检查开销
is 和 as 在泛型方法中的限制与绕过方式
泛型类型参数 T 默认无法直接用于 is 或 as,因为编译器不知道 T 是引用还是值类型。例如以下代码会报错:
T item = ...;
if (item is IDisposable) { ... } // ❌ CS0150
解决方法取决于需求:
- 加
class约束后可用as:where T : class→item as IDisposable - 加
unmanaged约束后不能用as,但可用typeof(T).IsAssignableFrom(...)配合反射(性能敏感场景慎用) - 最通用的是用
if (item is IDisposable disposable)+where T : IDisposable约束,让编译器静态保证 - .NET 5+ 支持
if (item is IAsyncDisposable)即使T无约束,前提是item实际运行时类型实现了该接口
没约束时硬要用,只能退回到 object 转换再判别,但失去泛型意义且有装箱成本。
容易被忽略的 null 引用与 nullable reference types 影响
启用 nullable reference types(#nullable enable)后,is 和 as 的行为不变,但编译器会对变量的 null 状态做更严格推断。例如:
string? s = GetMaybeNull();
if (s is string) {
Console.WriteLine(s.Length); // ✅ 此处 s 被推断为 non-nullable string
}
而如果漏掉 is 判断直接用 as:
string? s = null; var t = s as string; // t 是 string? 类型,不是 string!
此时 t 仍是可空的,后续调用 t.Length 会触发 warning(CS8602)。真正安全的做法是结合空合并或模式匹配:
if (s is string nonNullS) {
Console.WriteLine(nonNullS.Length); // ✅ nonNullS 是 string(non-nullable)
}
- 即使对象本身是
null,obj is SomeClass仍返回false,这是预期行为,不是 bug - 在 ASP.NET Core 模型绑定或 JSON 反序列化后对象字段为
null时,用as得到null,但若期望非空需额外校验 - 反序列化工具(如 System.Text.Json)默认不会调用构造函数,可能导致字段为
null,这时is判定可能不符合业务预期


















