Тривиальный выход из метода, который может выполнять асинхронный вызов - PullRequest
1 голос
/ 06 января 2020

У меня проблема с вызовом метода, который может возвращать Task<T> или null в зависимости от результата первоначального вызова синхронного поиска (это само по себе может быть анти-паттерном, поэтому, пожалуйста, дайте мне знать).

Я хочу вернуть 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);
}

Итак, я подумал, что мы всегда должен возвращать 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

Как вернуть пустышку Task<T>, которая не является результатом асинхронного c вызова?

Это даже правильный подход?

Ответы [ 2 ]

3 голосов
/ 06 января 2020

Просто верните задачу, которая содержит нулевое значение, как результат

return Task.FromResult<IGetUserCourseResponse>(null);
3 голосов
/ 06 января 2020

Было бы лучше, как вы предложили, вернуть Task<IGetUserCourseResponse>, в котором содержится null (или какое-либо другое значение часового). Вы можете создать такой завершенный Task с помощью 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: вместо метода, вызывающего это исключение напрямую, он вместо этого возвращает 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);
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...