如果参数是 T,转换为 T 会失败吗?

The*_*ern 2 c# casting

到目前为止,我一直认为,如果我检查参数是否“是”T,那么强制转换“as”T 应该是安全的。所以这总是会成功并且永远不会为空:

if (myParam is MyClass)
{
    MyClass instance = myParam as MyClass;
}
Run Code Online (Sandbox Code Playgroud)

但是,编译器警告我右侧可能为空:

“CS8600:将 null 文字或可能的 null 值转换为不可为 null 的类型。”

这真的会发生吗?还是编译器根本没有得到前面的检查?如果它仍然可以为空,这怎么可能呢?

根据微软文档,这似乎不可能: https://learn.microsoft.com/en-au/dotnet/csharp/language-reference/operators/type-testing-and-cast

形式的表达

东方

其中 E 是返回值的表达式,T 是类型或类型参数的名称,产生与以下相同的结果

E 是 T 吗?(T)(E) : (T)空

注意:(我以一种相当复杂的方式将 myParam 作为泛型类中的参数;原则上,如果需要的话,只要付出一点努力,我就可以创建一个最小的示例,但到目前为止我很确定,不存在这种情况演员阵容可能会失败。)

Swe*_*per 5

这是安全的。编译器警告是由于可为空引用类型功能引起的。

在分析表达式是否可以为 null 时,C# 仅对您执行的 null 检查进行控制流分析,而不对您执行的类型检查进行控制流分析。例如,C#可以这样理解:

if (myParam != null) {
    // C# understands that myParam is not null here
}
Run Code Online (Sandbox Code Playgroud)

但不是:

if (myParam is MyClass) {
    // C# does not understand that myParam is of type MyClass here
}
Run Code Online (Sandbox Code Playgroud)

因此,C# 认为该表达式myParam as MyClass为“maybe null”。它发现您正在将其分配给一个不可为空的变量instance,因此会出现警告。请参阅此处以供参考。

在旧版本的 C# 中,可空引用类型不存在,因此不会出现任何警告。每个引用类型都可以为空。

您应该使用声明模式来检查类型。

if (myParam is MyClass instance) {
    // use instance here...
}
Run Code Online (Sandbox Code Playgroud)