不可为空的引用类型:为什么编译器认为我的对象可以为空?

Jér*_*VEL 5 c# .net-core nullable-reference-types

我有一个项目,我在其中启用了新的Nullable 引用类型功能

 <Nullable>enable</Nullable>
Run Code Online (Sandbox Code Playgroud)

现在让我们考虑这段代码

public class Foo  {    }

var foo = new Foo();
Run Code Online (Sandbox Code Playgroud)

编译器认为该foo变量可以为空 ( Foo?)。这是为什么?我不明白。

现在启用 Nullable 引用类型功能后,返回的Foo对象不应为 null,因为它是不可为 null 的类型。

如果我希望它可以为空,我会指定它有一个 Foo?

那么为什么编译器说它是一个可为空的变量呢?

谢谢

编辑

这是我在这里描述的内容的屏幕截图。当您将鼠标悬停在foo变量上时

将 foo 变量悬停

can*_*on7 7

在最初的实现中,foo会被推断为Foo.

然而,人们抱怨这妨碍了以下事情:

string? GetThing() => ...

var result = "";
if (condition)
{
    result = GetThing();
}
Run Code Online (Sandbox Code Playgroud)

如果result推断为 a string,则该result = GetThing()行会导致警告:GetThing()返回 a string?,如果您尝试将 a 分配给 a string?,则会出现警告string

解决方案是推断result为 a string?,但编译器知道它当前不为空(其“流状态”为“NotNull”)。

这意味着:

string? GetThing() => ...

var result = "";

// No warning, as the compiler knows that result isn't null
int l1 = result.Length; 

if (condition)
{
    result = GetThing();
}

// Warning: the compiler knows 'result' might have been re-assigned
int l2 = result.Length; 
Run Code Online (Sandbox Code Playgroud)

有关工作中的流动状态的其他示例,请参阅以下内容:

string? result = GetString();
if (result == null)
    throw new Exception();

// No warning: the compiler knows that result can't be null here: if it was,
// the exception above would have been thrown
int l1 = result.Length;
Run Code Online (Sandbox Code Playgroud)
string? result = GetString();

// Warning: result might be null
int l1 = result.Length; 

// No warning: the compiler knows that result can't be null here: if it was,
// the line above would have thrown
int l2 = result.Length; 
Run Code Online (Sandbox Code Playgroud)
string result = "hello";
if (result == null)
    Console.WriteLine("NULL!");

// Warning: because we checked for null above, the compiler assumes that we
// know something that it doesn't, and so result might be null.
int l1 = result.Length;
Run Code Online (Sandbox Code Playgroud)

  • 老实说,这简直是愚蠢的。如果“var”关键字盲目地使每个引用类型都可以为空,那么您就会失去显式可为空类型的强度。似乎唯一的解决方案是显式地写出类型并完全避免使用“var”关键字,这很快就会变得乏味。我真的希望他们包含一个项目标志来禁用此行为。 (4认同)
  • 好的,谢谢你的回答。正如您所说,“解决方案是将结果推断为字符串?”,但编译器知道它当前不为空(其“流状态”为“NotNull”)`,但我呢?我的意思是现在我非常困惑,因为每次我将鼠标悬停在一个变量上时,它都会告诉我它是一个可以为空的变量,然后我必须检查这是否真的可以为空......有什么方法可以改变智能感知中的这种行为吗?或者是不使用“var”关键字的唯一方法? (2认同)
  • 现在,在我的代码中,我的反应都是“等等什么?!!” 这里的对象真的可以为空吗?啊不,这只是该死的编译器对我撒谎......` (2认同)