.NET非空引用类型和方法的out参数

Orw*_*wel 0 .net c# .net-core c#-8.0

我添加csproj以在C#8中启用Null引用类型:

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

此代码:

private static void Method()
{
    var dictionary = new Dictionary<string, string>();
    string value = string.Empty;

    dictionary.TryGetValue("Key", out value);
}
Run Code Online (Sandbox Code Playgroud)

TryGetValue行带有警告:warning CS8600:将空文字或可能的空值转换为非空类型。

我不明白为什么。TryGetValue的签名为:

    public bool TryGetValue(string key, [MaybeNullWhen(false)] out string value);
Run Code Online (Sandbox Code Playgroud)

该代码示例仅具有Non-Null引用。为什么会出现此错误?

can*_*on7 6

如果"Key"在字典中未找到,null则将为分配一个值value。但是,您已声明valuestring,这意味着它不应包含null。因此,编译器会向您发出警告。

最初分配string.Empty给您的事实value无关紧要-始终会被覆盖TryGetValue(并且您应该得到另一个警告,指出该事实)。

您应声明value为a string?,以指示其值可能为null

请注意,编译器非常聪明。如果您写:

if (!dictionary.TryGetValue("Key", out string? value))
{
    value = string.Empty;
}
Run Code Online (Sandbox Code Playgroud)

那么编译器就会知道value不能为null,并且如果您尝试在其上调用方法,它也不会抱怨。


Orw*_*wel 2

来自文档C# 编译器解释的空状态静态分析的属性

在可空启用的上下文中,编译器执行代码的静态分析以确定所有引用类型变量的空状态:

  • not-null:静态分析确定变量具有非空值。
  • Maybe-null:静态分析无法确定为变量分配了非空值。

静态分析器认为变量可以是:

  • 可为空的
  • 不可为空
  • 也许可以为空

当一个不可为空的变量用属性MaybeNull修饰时,静态分析器认为该变量可能可以为空。

[return: MaybeNull]
static string Find(string key)
{
    return key == "" ? null : key;
}

string value1 = Find("key"); // Warning CS8600 Converting null literal or possible null value to non-nullable type.
string? value2 = Find("key"); // No warning
var value3 = Find("key"); // The inferred type is 'string?'
Run Code Online (Sandbox Code Playgroud)

MaybeNullWhen属性类似,但静态分析器可以根据方法的结果处理检查

static bool TryGetValue(string key, [MaybeNullWhen(false)] out string value)
{
    if(key == "")
    {
        value = null;
        return false;
    }
    value = "Foo";
    return true;
}

string notnullable;

string value1;
if (TryGetValue("Key", out value1)) // Warning CS8600 Converting null literal or possible null value to non-nullable type.
    notnullable = value1;
else
    notnullable = value1; // Warning CS8600 Converting null literal or possible null value to non-nullable type.

string? value2;
if (TryGetValue("Key", out value2))
    notnullable = value2;
else
    notnullable = value2; // Warning CS8600 Converting null literal or possible null value to non-nullable type.
Run Code Online (Sandbox Code Playgroud)

我同意,这在这个例子中没有意义。但使用泛型方法时,您可以指定不可为 null 的类型,而该方法可以返回/设置 null:

[return: MaybeNull]
static T Find<T>(string key);
static bool TryGetValue<T>(string key, [MaybeNullWhen(false)] out T value)
Run Code Online (Sandbox Code Playgroud)