可以/应该将Task <tresult>包装在C#5.0中,等待TResult中的协变吗?</tresult>

时间:2012-08-30 20:13:08

标签: c# task-parallel-library covariance async-await c#-5.0

我真的很喜欢使用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接口,但我想我可以创建一个并创建一个扩展方法,转换为一个包装的,协变的,可用的任务对象。或者我做错了吗?

2 个答案:

答案 0 :(得分:12)

Task<T>T中无法协变,因为它是一个类。只有接口和代理可以有通用差异。

至于是否值得做包装......我想这取决于你在项目中使用协方差的程度。我怀疑你会发现随着时间的推移会让所有的包装和展开混乱,说实话 - 如果它不是不好只是为了消除协方差,我会这样做。

答案 1 :(得分:5)

我认为在ITask界面上不包括对async关键字的编译器支持是微软的一个主要疏忽。幸运的是,解决这个限制并不是很难。

我已经实现了一个协变的等待ITask<out TResult>接口。它的用法非常简单。

更多信息可在以下网址找到:

https://github.com/jam40jeff/ITask