.NET 不可为 null 的引用类型和输出参数
.NET non-nullable reference type and out parameters
我修改了 csproj
文件以在 C#8 中启用空引用类型:
<Nullable>enable</Nullable>
给定以下代码:
private static void Method()
{
var dictionary = new Dictionary<string, string>();
string value = string.Empty;
dictionary.TryGetValue("Key", out value);
}
带有TryGetValue()
的行给出了警告:
CS8600
: Converting null literal or possible null value to non-nullable type.
我不明白为什么。 TryGetValue()
的签名是:
public bool TryGetValue(string key, [MaybeNullWhen(false)] out string value);
代码示例只有不可为空的引用。为什么会出现此错误?
如果在字典中找不到 "Key"
,则 null
的值将分配给 value
变量。但是,您已将 value
声明为 string
,这意味着它不应包含 null
。因此编译器给你一个警告。
您最初将 string.Empty
分配给 value
的事实并不重要 - 它总是会被 TryGetValue
覆盖(并且您应该收到另一个警告,上面写着).
您应该将 value
声明为 string?
,以表明它的值可能是 null
。
请注意,编译器非常智能。如果你写:
if (!dictionary.TryGetValue("Key", out string? value))
{
value = string.Empty;
}
然后编译器知道 value
不能是 null
,如果您随后尝试调用它的方法,它也不会报错。
canton7的答案是正确的(+1)。
这不是解释,而是解决方法:
您可以像这样向 Dictionary<TVey, TValue>
添加扩展方法:
public static bool TryGetValue<TKey, TValue>(this Dictionary<TKey, TValue> dictionary, TKey key, TValue @default, out TValue @value) where TKey : notnull
{
var result = dictionary.TryGetValue(key, out var val);
@value = result ? val : @default;
return result;
}
然后你可以这样使用它:
private static void Method()
{
var dictionary = new Dictionary<string, string>();
/// populate dictionary here...
dictionary.TryGetValue("Key", string.Empty, out var value);
}
这应该使您能够将 value
保留为不可为 null 的字符串。
来自文档 Attributes for null-state static analysis interpreted by the C# compiler。
In a nullable enabled context, the compiler performs static analysis of code to determine the null-state of all reference type variables:
- not-null: Static analysis determines that a variable has a non-null value.
- maybe-null: Static analysis can't determine that a variable is assigned a non-null value.
静态分析器认为一个变量可以是:
- 可为空
- 不可为空
- 可能为空
当一个不可为空的变量用属性 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?'
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.
我同意,这在这个例子中没有意义。但是使用泛型方法,您可以指定一个不可为 null 的类型,而该方法可以 return/set null:
[return: MaybeNull]
static T Find<T>(string key);
static bool TryGetValue<T>(string key, [MaybeNullWhen(false)] out T value)
我修改了 csproj
文件以在 C#8 中启用空引用类型:
<Nullable>enable</Nullable>
给定以下代码:
private static void Method()
{
var dictionary = new Dictionary<string, string>();
string value = string.Empty;
dictionary.TryGetValue("Key", out value);
}
带有TryGetValue()
的行给出了警告:
CS8600
: Converting null literal or possible null value to non-nullable type.
我不明白为什么。 TryGetValue()
的签名是:
public bool TryGetValue(string key, [MaybeNullWhen(false)] out string value);
代码示例只有不可为空的引用。为什么会出现此错误?
如果在字典中找不到 "Key"
,则 null
的值将分配给 value
变量。但是,您已将 value
声明为 string
,这意味着它不应包含 null
。因此编译器给你一个警告。
您最初将 string.Empty
分配给 value
的事实并不重要 - 它总是会被 TryGetValue
覆盖(并且您应该收到另一个警告,上面写着).
您应该将 value
声明为 string?
,以表明它的值可能是 null
。
请注意,编译器非常智能。如果你写:
if (!dictionary.TryGetValue("Key", out string? value))
{
value = string.Empty;
}
然后编译器知道 value
不能是 null
,如果您随后尝试调用它的方法,它也不会报错。
canton7的答案是正确的(+1)。
这不是解释,而是解决方法:
您可以像这样向 Dictionary<TVey, TValue>
添加扩展方法:
public static bool TryGetValue<TKey, TValue>(this Dictionary<TKey, TValue> dictionary, TKey key, TValue @default, out TValue @value) where TKey : notnull
{
var result = dictionary.TryGetValue(key, out var val);
@value = result ? val : @default;
return result;
}
然后你可以这样使用它:
private static void Method()
{
var dictionary = new Dictionary<string, string>();
/// populate dictionary here...
dictionary.TryGetValue("Key", string.Empty, out var value);
}
这应该使您能够将 value
保留为不可为 null 的字符串。
来自文档 Attributes for null-state static analysis interpreted by the C# compiler。
In a nullable enabled context, the compiler performs static analysis of code to determine the null-state of all reference type variables:
- not-null: Static analysis determines that a variable has a non-null value.
- maybe-null: Static analysis can't determine that a variable is assigned a non-null value.
静态分析器认为一个变量可以是:
- 可为空
- 不可为空
- 可能为空
当一个不可为空的变量用属性 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?'
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.
我同意,这在这个例子中没有意义。但是使用泛型方法,您可以指定一个不可为 null 的类型,而该方法可以 return/set null:
[return: MaybeNull]
static T Find<T>(string key);
static bool TryGetValue<T>(string key, [MaybeNullWhen(false)] out T value)