【发布时间】:2020-01-29 14:50:55
【问题描述】:
我有一个这样的扩展方法:
[return: MaybeNull]
public static TValue GetValueOrDefault<TKey, TValue>(this IDictionary<TKey, TValue> dictionary, TKey key)
where TKey : notnull
where TValue : notnull {
if (dictionary.TryGetValue(key, out TValue value)) return value;
else return default!;
}
这很好用。如果我称它为期望非空值,编译器会警告我结果可能为空,这正是我想要的。
但是,如果我有另一个调用GetValueOrDefault 的方法,而我忘记添加[return: MaybeNull],编译器根本不会警告我。这是一个令人费解的例子,只是为了解释我的问题:
public static TValue SomeOtherMethod<TKey, TValue>(this IDictionary<TKey, TValue> dictionary, TKey key)
where TKey : notnull
where TValue : notnull
=> dictionary.GetValueOrDefault(key); // No warning this could be null
...
var dictionary = new Dictionary<string, string>() {
["hello"] = "world"
};
string s1 = dictionary.GetValueOrDefault("foo"); // Compiler warning
string s2 = dictionary.SomeOtherMethod("foo"); // No compiler warning
int s2Len = s2.Length; // Visual Studio states "s2 is not null here", even though it absolutely is!
我对 C# 8.0 可空引用类型非常陌生,尤其是涉及泛型。有什么我想念的东西才能让它工作吗?如果没有编译器警告,感觉就像它违背了使用 C# 8.0 可空类型的目的。我陷入了一种错误的安全感,我不可能错过 NullReferenceException,尤其是当 Visual Studio 向我保证“s2 在此处不为空”时,即使它绝对是。
【问题讨论】:
-
我认为,
TKey和TValue的原因可以在您的示例中引用值类型。而编译器根本不知道,类型本身是否可以在运行时 -
这是真的;如果我改用
where TValue : class,并设置了返回类型TValue?,编译器会警告我。但是 TValue 并不总是一个类;有时我的 IDictionary 上有值类型。 -
你可以参考这个document,尤其是
notnull泛型约束和T?问题部分
标签: c# generics c#-8.0 nullable-reference-types