我真的很喜欢使用C#5.0异步编程。但是,有些地方更新旧代码以与TAP模型保持一致会给我带来问题。
这是其中之一 - 我不确定为什么Task<TResult>
在TResult中不是协变的,但在尝试更新协变接口以从同步模式转变为异步模式时,它会给我带来问题: / p>
旧代码:
public interface IInitializable<out T> // ** out generic modifier **
{
/// <summary>
/// Boolean to indicate if class is ready
/// </summary>
bool IsInitialized { get; }
/// <summary>
/// Calls for instance to be initialized using current parameters
/// Driver initialization can be done in the default constructor if desired
/// </summary>
T Initialize();
}
新代码(不会编译):
public interface IAsyncInitializable<out T> // ** out generic modifier...broken **
{
/// <summary>
/// Boolean to indicate if class is ready
/// </summary>
bool IsInitialized { get; }
/// <summary>
/// Calls for instance to be initialized using current parameters
/// Driver initialization can be done in the default constructor if desired
/// </summary>
Task<T> InitializeAsync(); // ** breaks because Task<TResult> is invariant in TResult **
}
如果没有彻底修改我的API,是否有合理的解决方法? (加分:为什么Task不协变?)。没有IAwaitable接口,但我想我可以创建一个并创建一个扩展方法,转换为一个包装的,协变的,可用的任务对象。或者我做错了吗?
答案 0 :(得分:12)
Task<T>
在T
中无法协变,因为它是一个类。只有接口和代理可以有通用差异。
至于是否值得做包装......我想这取决于你在项目中使用协方差的程度。我怀疑你会发现随着时间的推移会让所有的包装和展开混乱,说实话 - 如果它不是太不好只是为了消除协方差,我会这样做。
答案 1 :(得分:5)
我认为在ITask界面上不包括对async关键字的编译器支持是微软的一个主要疏忽。幸运的是,解决这个限制并不是很难。
我已经实现了一个协变的等待ITask<out TResult>
接口。它的用法非常简单。
更多信息可在以下网址找到: