从另一个泛型方法中调用MaybeNull泛型方法

4

我有一个类似这样的扩展方法:

[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,但这却是一种错误的安全感。


我认为你的例子中TKeyTValue可以是值类型的引用,编译器无法确定类型本身是否可以在运行时。 - Pavel Anikhouski
没错,如果我使用where TValue : class,并将返回类型设置为TValue?,编译器会很好地警告我。但是TValue并不总是一个类;我有时在我的IDictionary上有值类型。 - Ber'Zophus
您可以参考此文档,特别是其中的“notnull泛型约束”和“T?问题”部分。 - Pavel Anikhouski
您还可以查看现有的线程,例如此处此处。看起来MaybeNull是最佳选择,您应该使用它来帮助编译器识别正确的返回类型。 - Pavel Anikhouski
1个回答

0

这个已经在较新的编译器版本中得到了改进(仍然是 C# 8,只是更新的编译器)。如果您使用更新的 Visual Studio,您会有一个更新的编译器。

这是您的例子:

https://sharplab.io/#v2:EYLgtghgzgLgpgJwD4GIB2BXANliwtwAEcaeBAsAFBUACADITQIwAsA3LQ8wHQAiAlhADmaAPax+AYyjcAwqIAmcAIKksATyj8oHapRoBmRkwBsjAEyFZhAN5VCDxkeZmaLQgFkAFAEpb9xwBfAIcQwgBtGgB2EE8IdWA4ADlsLABdMMNjMwAVADUILAwiAHE4GAKiuAB5BF44ADMIbBgAHhyAaTh1ABpCfMLigD4vGAALbUIASQFJGH5RUgR1dq7e/srhwgUpecWIZb7O7sIAa26fMMdCAHcxxCJj9UJYsRhMHCvHO4eNwaJXqJ3qkwnZKNdrvwGoQvDs5gslupuDllmUKv8vOd1qIMDA/lVCAA3f4+S7giEU6JE/66CkOOBYKBwL6UqLbRrNLAwWlBMKZZymfHFQgAZVEYBq40QHnKY0Uq26R02cBG40mM12CIOKyeSv+Q22mv2h36azOFxZt3uCEeZsBwM+5IpPxtQoBhDeHywYQAvAa4XtEdw0cravUmi1MRc2IQAPSxwhJUS3A5ofhoISENVQQiSHFYBSERIekGUQJAA===

有两个改进:

  1. 您不需要对GetValueOrDefaultdefault加上!,因为分析现在尊重MaybeNull属性。
  2. 您现在会收到警告CS8603(可能的空引用返回),在此之前,您指出您没有收到警告但确实应该。

升级了Visual Studio到16.5.4版本,并确认它修复了问题。非常感谢! - Ber'Zophus

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接