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