c# - `is` 运算符和转换为泛型类型有什么区别?
问题描述
为什么第一个函数编译而第二个函数发出警告?这两个实现不等效吗?的类型valT
在T
两种实现中都有。
https://dotnetfiddle.net/XV5AXU
T To1<T>(object? val)
{
if (!(val is T valT))
{
throw new InvalidCastException();
}
return valT;
}
T To2<T>(object? val)
{
var valT = (T)val;
return valT; // Possible null reference return
}
解决方案
前言:你可能不需要实现一个通用的“Cast”方法。在 C# 中实现泛型方法以提高性能时要小心,以避免装箱(避免使用object
)。此外,如果您在泛型方法中隐藏实际的显式转换运算符,则 C# 编译器无法提前警告消费代码,即转换可能是不正确的。
考虑:
Int32 i = new Int32();
String s = (String)o; // <-- CS0030 Cannot convert type 'int' to 'string'
但是使用您的代码:
Int32 i = new Int32();
String s1 = To1<String>( i ); // No compiler error, despite incompatible types.
String s2 = To2<String>( i ); // Also no compiler error.
至于你的问题:
这两个实现不等效吗?
不。看看你通过时会发生什么val: null
:
// Using your functions `To1` and `To2`:
String strFromObj = To1<String>( new Object() ); // throws InvalidCastException (thrown from your code)
String strFromNull = To1<String>( null ); // throws InvalidCastException (thrown from your code)
String strFromObj = To2<String>( new Object() ); // throws InvalidCastException (thrown from the operator)
String strFromNull = To2<String>( null ); // returns null;
为什么第一个函数编译而第二个函数发出警告?
- 您的第一个函数使用
is
运算符,它是安全的并且永远不会抛出(请注意,在这种情况下抛出的是您的代码InvalidCastException
)。 - 您的第二个函数盲目地使用强制转换表达式而没有先进行类型检查,因此它是不安全的,因为运算符本身会抛出
InvalidCastException
ifT
不正确,除非操作数是null
.
foo is T bar
运算符测试非null
值的类型。如果foo
是null
,则is
表达式返回 false 和bar
isdefault(T)
。T bar = (T)foo
强制转换表达式将强制转换null
值,但前提T
是它是引用类型 - 但此语法也可能调用自定义显式转换运算符而不是执行强制转换。
另请注意,C# 8.0 的 nullable-reference-types 功能 ( object?
) 在运行时未强制执行:编译器不会将throw new ArgumentNullException
语句添加到已编译的代码中,因此如果您更改代码以使用object
而不是object?
您仍应添加if( val is null ) throw new ArgumentNullException( nameof(val) );
.
推荐阅读
- java - 如何根据标准使用 Java 8 流删除重复项
- node.js - 节点未重定向到页面未找到 404
- ruby-on-rails - Rails 未从此操作返回
- python - 调试 python django 项目
- c - 尽管有足够的可用内存 (32 GB),但在 malloc() 处理 12 GB 内存后收到“分段错误:11”
- php - Facebook OAuth 一次又一次地请求许可
- bash - 编写一个 shell 脚本,该脚本将返回您的存储库 git 跳过的文件列表
- embedded - STM32 上的 Eigen 只能工作到一定大小
- matlab - griddata 在所需区域之外生成数据
- javascript - 即使有结果,Promise 也会返回未定义的值