【问题标题】:Calling a MaybeNull generic method from another generic method从另一个泛型方法调用 MaybeNull 泛型方法
【发布时间】: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 在此处不为空”时,即使它绝对是。

【问题讨论】:

  • 我认为,TKeyTValue 的原因可以在您的示例中引用值类型。而编译器根本不知道,类型本身是否可以在运行时
  • 这是真的;如果我改用where TValue : class,并设置了返回类型TValue?,编译器会警告我。但是 TValue 并不总是一个类;有时我的 IDictionary 上有值类型。
  • 你可以参考这个document,尤其是notnull泛型约束T?问题部分
  • 您还可以查看现有线程,例如thisthis。看来,MaybeNull 是这里的最佳选择,您应该使用它来帮助编译器识别正确的返回类型

标签: c# generics c#-8.0 nullable-reference-types


【解决方案1】:

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

这是你的例子:

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

有两个改进:

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

【讨论】:

  • 将 Visual Studio 升级到 16.5.4,并确认已解决问题。非常感谢!
猜你喜欢
  • 2011-04-23
  • 2011-05-18
  • 1970-01-01
  • 1970-01-01
  • 2016-06-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-04-21
相关资源
最近更新 更多