我有一个类似这样的扩展方法:
[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的可空类型就失去了意义。当Visual Studio告诉我“s2在这里不为null”,而实际上它确实为null时,我会认为自己不可能错过NullReferenceException,但这却是一种错误的安全感。
TKey
和TValue
可以是值类型的引用,编译器无法确定类型本身是否可以在运行时。 - Pavel Anikhouskiwhere TValue : class
,并将返回类型设置为TValue?
,编译器会很好地警告我。但是TValue并不总是一个类;我有时在我的IDictionary上有值类型。 - Ber'Zophusnotnull
泛型约束”和“T?
问题”部分。 - Pavel AnikhouskiMaybeNull
是最佳选择,您应该使用它来帮助编译器识别正确的返回类型。 - Pavel Anikhouski