从可能执行异步调用的方法中轻松退出



我在调用方法时遇到问题,该方法可能会返回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>

这甚至是正确的方法吗?

正如您所建议的,最好返回一个包含null(或其他一些哨兵值(Task<IGetUserCourseResponse>。您可以使用Task.FromResult((IGetUserCourseResponse)null)创建这样一个完整的Task

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);
}

只需返回一个保存空值作为结果的任务

return Task.FromResult<IGetUserCourseResponse>(null);

相关内容

  • 没有找到相关文章

最新更新