C# 从另一个泛型方法调用MaybeNull泛型方法

C# 从另一个泛型方法调用MaybeNull泛型方法,c#,generics,c#-8.0,nullable-reference-types,C#,Generics,C# 8.0,Nullable Reference Types,我有这样一个扩展方法: [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: 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!;
}

我对C#8.0可空引用类型非常陌生,尤其是涉及泛型的引用类型。我还缺什么东西来让它工作吗?在没有编译器警告的情况下,感觉它违背了使用C#8.0可空类型的目的。我陷入了一种错误的安全感,我不可能错过NullReferenceException,特别是当Visual Studio向我保证“s2在这里不是空的”时,尽管它绝对是空的。

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

以下是您的示例:

有两项改进:

  • 你不需要
    默认值
    ,因为分析现在考虑了
    GetValueOrDefault
    上的
    MaybeNull
    属性
  • 您现在得到了警告CS8603(可能的空引用返回),您以前指出您没有得到警告,但应该得到警告

  • 我认为,在您的示例中,
    TKey
    TValue
    的原因可能是值类型的引用。编译器根本不知道类型本身是否可以在运行时,这是真的;如果我改为使用
    where TValue:class
    ,并将返回类型设置为
    TValue?
    ,编译器会很好地警告我。但TValue并不总是一个类;有时我的IDictionary上有值类型。您可以参考这一点,尤其是
    notnull
    通用约束和
    T?
    部分的问题。您还可以查看现有线程,如或。似乎,
    MaybeNull
    是这里的最佳选择,您应该使用它来帮助编译器识别正确的返回类型将Visual Studio升级到16.5.4,并确认它修复了问题。非常感谢!
    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!