class ResultBase {}
class Result : ResultBase {}
Task<ResultBase> GetResult() {
return Task.FromResult(new Result());
}
编译器告诉我它无法将 Task<Result>
隐式转换为 Task<ResultBase>
。有人能解释一下为什么吗?我本来以为协变会让我以这种方式编写代码。class ResultBase {}
class Result : ResultBase {}
Task<ResultBase> GetResult() {
return Task.FromResult(new Result());
}
编译器告诉我它无法将 Task<Result>
隐式转换为 Task<ResultBase>
。有人能解释一下为什么吗?我本来以为协变会让我以这种方式编写代码。根据消息灵通的人的说法...
正当性在于,协变性的优势被杂乱无序的缺点所抵消(即每个人都必须决定是否在代码的每个地方使用Task还是ITask)。
对我来说,似乎没有非常令人信服的动机。 ITask<out T>
将需要很多新的重载,可能会在底层有相当大的影响(我不能证明实际基类的实现方式或者它与天真实现相比有多特殊),但在这些linq
类似的扩展方法中需要更多的工作。
其他人提出了一个好观点 - 把时间花在使class
具有协变性和逆变性上会更好。我不知道那会有多难,但对我来说,那听起来是更好的时间利用方式。
另一方面,有人提到在async
方法中添加一个真正的yield return
特性会非常酷。我的意思是,不需要任何巧妙的手法。
async
与await
依赖于存在一个适当的GetAwaiter
方法,因此它已经与Task
类解耦。 - LeeTask
、Task<>
、IAsyncEnumerable<>
或IAsyncEnumerator<>
。仅具有GetAwaiter
方法的类是不够的。至少编译器是这么说的。 - Francisco Netoasync
/await
只依赖于存在一个返回一个具有适当签名的 IsCompleted
、OnCompleted
和 GetResult
成员的对象的 GetAwaiter
方法。因此,可自定义等待方法的实现。请参见此处。 - Luke Caswell Samuel我意识到我来晚了,但是这里有一个扩展方法,我一直在使用它来解决这个缺失的功能:
/// <summary>
/// Casts the result type of the input task as if it were covariant
/// </summary>
/// <typeparam name="T">The original result type of the task</typeparam>
/// <typeparam name="TResult">The covariant type to return</typeparam>
/// <param name="task">The target task to cast</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static async Task<TResult> AsTask<T, TResult>(this Task<T> task)
where T : TResult
where TResult : class
{
return await task;
}
class ResultBase {}
class Result : ResultBase {}
Task<Result> GetResultAsync() => ...; // Some async code that returns Result
Task<ResultBase> GetResultBaseAsync()
{
return GetResultAsync().AsTask<Result, ResultBase>();
}
Task.FromResult<ResultBase>(new Result());
- Bluuuwhere TResult : class
? - chtenb.AsTask()
即可将ITask转换为Task(反向扩展方法也包含在该包中)。请注意保留HTML标签。 [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static async Task<T> AsTask<T>(this Task task)
{
var taskType = task.GetType();
await task;
return (T)taskType.GetProperty("Result").GetValue(task);
}
Task
不是 Task<T>
,则会失败。 - Dai
Task.FromResult<ResultBase>(new Result())
。它可以编译通过。但是,是的,Task
是逆变的,这很糟糕。 - ps_ttf