【问题标题】:Tell the caller that a `async Task<T>` method may return null告诉调用者 `async Task<T>` 方法可能返回 null
【发布时间】:2020-10-02 10:09:44
【问题描述】:

我的情况与Proper nullable annotation for async generic method that may return default(T)描述的情况类似。

但是,我想知道让调用者知道“返回值”可能为空的正确方法。

    public async Task<T> GetAsync<T>()
    {
        // sometimes returns default(T)!;
    }

如果这不是异步方法,我可以使用 MaybeNull 属性。

    [return: MaybeNull]
    public T Get<T>()
    {
        // sometimes returns default(T)!;
    }

如果它不是通用的,我可以使用? 语法。

    public async Task<string?> GetAsync()
    {
        // sometimes returns default(string)!;
    }

有没有办法让调用者知道它可以为空而不添加通用约束?

编辑: 为了澄清,我的意思是让编译器知道任务中的值可能为空。 我想反过来也是正确的。 我最感兴趣的是它应该如何与新的 C# 可为空引用语法一起工作。

我可以做这样的事情就好了

    var a = await GetAsync<string?>(); // a is null
    var b = await GetAsync<int?>(); // b is null
    var c = await GetAsync<string>(); // c is null.  Wait string is not supposed to be null and the compiler won't warn you if you use it!
    var d = await GetAsync<int>(); // d is 0

编辑: 我可以做这样的事情就好了

    var a = await Get<string?>(); // a is null
    var b = await Get<int?>(); // b is null
    var c = await Get<string>(); // c is null.  
    var d = await Get<int>(); // d is 0

Nullable reference types: How to specify "T?" type without constraining to class or struct 的建议类似,但可以修改 Box 类以在我无法更改 Task 实现的情况下提供适当的警告。

【问题讨论】:

标签: c# generics async-await nullable-reference-types


【解决方案1】:

在 C# 8 中,您无法表达这一点,因为您无法将 [MaybeNull] 属性应用于 Task&lt;T&gt; 的类型参数。

在 C# 9 中,您只需将返回类型设为可为空。

public async Task<T?> GetAsync<T>()
{
    // sometimes returns default(T)!;
}

【讨论】:

    【解决方案2】:

    这里类似话题:Nullable type as a generic parameter possible?

    这里的问题是我们不知道T 是什么类型,我的意思是它是类还是结构。如果它总是结构比我建议使用Nullable&lt;T&gt; 或T? 与constaraint where T : struct。但是如果它可以是定义类,则类可以为空,因为它是引用类型。

    如果没有约束,你可以告诉调用者他会得到什么的唯一方法是使用 /// &lt;summary&gt; 作为 itsme86 提到的或给方法更有意义的名称,例如。 GetOrDefaultAsync()

    编辑: 参考 Stefan 的回答,使用一些函数式编程技巧并为返回类型创建包装器来指示返回的对象是否具有值是一个很好的解决方案。

    【讨论】:

    • 这并不完全正确,因为我们在非异步方法上也有同样的问题,但您可以使用属性告诉编译器结果可能为 null。
    • 在这种特殊情况下需要使用的属性,但是不允许在源代码中使用。您可以声明一个可能欺骗编译器的属性副本,但是当您尝试使用它时,您会被告知“CS8623:不允许显式应用 'System.Runtime.CompilerServices.NullableAttribute'。”
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-09-23
    • 2016-09-23
    • 1970-01-01
    • 2020-05-03
    • 2016-10-05
    • 2023-03-13
    相关资源
    最近更新 更多