从可能执行异步调用的方法中简单退出

Trivial exit from an method that may perform an asynchronous call

我在调用可能 return Task<T>null 的方法时遇到问题,具体取决于初始同步查找调用的结果(这本身可能是反-模式所以请告诉我)。

如果出现简单的退出条件,我有点想 return null 但这会导致调用(外部)方法失败,因为外部调用需要 Task<T> 响应(琐碎的出口)被推到 ConfigureAwait(true) 随后产生 NullReferenceException.

外调用方式:

var res = await MyService.GetUserCourseStatusAsync(userID, productID).ConfigureAwait(true);

中间方法:

public Task<IGetUserCourseResponse> GetUserCourseStatusAsync(int userID, int productID)
{
    // Look up User's ID (if exists)
    var userCredentials = GetUserCredentials(userID);

    if (userCredentials?.UserID == null)
        return null; // Trivial return of null ("User not registered"). *** This causes exception on ConfigureAwait(true) above ***

    // Another synchronous call
    var courseId = GetCourseID(productID);

    if (courseId == null)
        throw new InvalidOperationException($"Product #{productID} is not a course");

    // Asynchronous call to inner method (this bit works fine)
    return GetUserCourseAsync(userCredentials.UserID.Value, courseId.Value);
}

所以我当时的想法是我们应该总是 return 一个 Task<T> 而不是 null。 但是,所有这些都会导致编译错误:

//return null; // Trivial return of null ("User not registered"). *** This causes exception 

// Compile error: CS0029: Cannot implicitly convert type 'GetUserCourseInner' to 'System.Threading.Tasks.Task<IGetUserCourseResponse>'
return new GetUserCourseInner(); // Not registered

// Compile error: CS1503    Argument 1: cannot convert from 'GetUserCourseInner' to 'System.Func<IGetUserCourseResponse>'
return new Task<IGetUserCourseResponse>(new GetUserCourseInner()); // Not registered

如何 return 不是异步调用结果的虚拟 Task<T>

这是正确的方法吗?

如您所建议,return 一个 Task<IGetUserCourseResponse> 包含 null(或其他标记值)会更好.您可以创建这样一个完整的 Task with Task.FromResult((IGetUserCourseResponse)null):

public Task<IGetUserCourseResponse> GetUserCourseStatusAsync(int userID, int productID)
{
    // Look up User's ID (if exists)
    var userCredentials = GetUserCredentials(userID);
    if (userCredentials?.UserID == null)
        return Task.FromResult((IGetUserCourseResponse)null);

    // Another synchronous call
    var courseId = GetCourseID(productID);
    if (courseId == null)
        throw new InvalidOperationException($"Product #{productID} is not a course");

    // Asynchronous call to inner method (this bit works fine)
    return GetUserCourseAsync(userCredentials.UserID.Value, courseId.Value);
}

或者,您可以创建外部方法 async注意 但是,这会在抛出 InvalidOperationException 的情况下改变其行为:而不是直接抛出此异常的方法,而是 return a Task 其中包含此异常。这个不一定是你想要的:

public async Task<IGetUserCourseResponse> GetUserCourseStatusAsync(int userID, int productID)
{
    // Look up User's ID (if exists)
    var userCredentials = GetUserCredentials(userID);
    if (userCredentials?.UserID == null)
        return null;

    // Another synchronous call
    var courseId = GetCourseID(productID);
    if (courseId == null)
        throw new InvalidOperationException($"Product #{productID} is not a course");

    // Asynchronous call to inner method (this bit works fine)
    return await GetUserCourseAsync(userCredentials.UserID.Value, courseId.Value);
}

只是 return 一个包含空值作为结果的任务

return Task.FromResult<IGetUserCourseResponse>(null);