可以将其转换为 T,如果参数是 T,则失败吗?

huangapple go评论72阅读模式
英文:

Can cast as T fail if parameter is T?

问题

直到现在,我一直认为如果我检查一个参数是否为 "is" T,那么一个 "as" T 的转换应该是安全的。因此,这应该总是成功的,不会为空:

if (myParam is MyClass)
{
    MyClass instance = myParam as MyClass;
}

然而,编译器警告我右边的值可能为空:

"CS8600: Converting null literal or possible null value to non-nullable type."

这是否真的可能发生,还是编译器只是没有理解前面的检查?如果它仍然可能为空,这怎么可能呢?

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

表达式形式

E as T

其中 E 是返回值的表达式,T 是类型的名称或类型参数的名称,产生与

E is T ? (T)(E) : (T)null
相同的结果

注意:(我以一种相当复杂的方式将myParam作为参数传递给一个泛型类;原则上,如果有必要,我可以创建一个最小的示例,但直到现在我相当确定在这种情况下这种转换永远不会失败。)

英文:

Up to now I always thought that if I check if a parameter "is" T, then a cast "as" T should be safe. So this would always succeed and never be null:

if (myParam is MyClass)
{
    MyClass instance = myParam as MyClass;
}

However, the compiler warns me that the right hand side might be null:

"CS8600: Converting null literal or possible null value to non-nullable type."

Can this actually happen or does the compiler simply not get the preceding check? And if it still could be null, how would this be possible?

According to the Microsoft documentation, it seems impossible:
https://learn.microsoft.com/en-au/dotnet/csharp/language-reference/operators/type-testing-and-cast

>The expression of the form
>
> E as T
>
>where E is an expression that returns a value and T is the name of a type or a type parameter, produces the same result as
>
>E is T ? (T)(E) : (T)null

Note: (I get myParam as parameter in a generic class in a quite complicated way; in principle, with a bit of effort I can create a minimum example if necessary, but I was quite sure up to now that there is no situation where this cast could ever fail.)

答案1

得分: 5

以下是翻译好的内容:

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

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

if (myParam != null) {
    // C# understands that myParam is not null here
}

但不是:

if (myParam is MyClass) {
    // C# does not understand that myParam is of type MyClass here
}

因为这个原因,C#认为表达式myParam as MyClass可能为null。而且它看到您将其分配给一个非可空变量instance,所以会出现警告。请参见这里以获取参考信息。

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

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

if (myParam is MyClass instance) {
    // 在这里使用instance...
}
英文:

This is safe. The compiler warning is due to the nullable reference types feature.

When analysing whether an expression can be null, C# only does control flow analysis for the null-checks that you did, and not the type checks that you did. For example, C# can understand this:

if (myParam != null) {
    // C# understands that myParam is not null here
}

But not:

if (myParam is MyClass) {
    // C# does not understand that myParam is of type MyClass here
}

Because of this, C# thinks that the expression myParam as MyClass is "maybe null". And it sees that you are assigning it to a non-nullable variable instance, hence the warning. See here for a reference.

In older versions of C#, nullable reference types weren't a thing, so there were no warnings for this. Every reference type were nullable.

You should check the type with a declaration pattern instead.

if (myParam is MyClass instance) {
    // use instance here...
}

huangapple
  • 本文由 发表于 2023年5月15日 11:46:36
  • 转载请务必保留本文链接:https://go.coder-hub.com/76250773.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定