我修改了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
:将null文本或可能的null值转换为不可为null的类型。
我不明白为什么。TryGetValue()
的签名为:
public bool TryGetValue(string key, [MaybeNullWhen(false)] out string value);
代码示例只有不可为null的引用。为什么会出现此错误?
如果在字典中找不到"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的字符串。
来自C#编译器解释的空状态静态分析的文档属性。
在启用了null的上下文中,编译器对代码执行静态分析,以确定所有引用类型变量的null状态:
- not null:静态分析确定变量具有非null值
- maybe null:静态分析无法确定变量是否分配了非null值
静态分析器认为变量可以是:
- 可以为null
- 不可为null
- 可能为null
当用属性MaybeNull修饰不可为null的变量时,静态分析器认为该变量可能为null。
[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的类型,而该方法可以返回/设置null:
[return: MaybeNull]
static T Find<T>(string key);
static bool TryGetValue<T>(string key, [MaybeNullWhen(false)] out T value)