任务是否可以/应该包装在 C# 5.0 中,该 C<TResult># 5.0 在 TResult 中是协变的?



我真的很喜欢使用C#5.0异步编程。然而,在一些地方,更新旧代码以与TAP模型保持一致会给我带来问题

这里有一个-我不确定为什么Task<TResult>在TResult中不是协变的,但当我试图更新协变接口以从同步模式移动到异步模式时,它给我带来了问题:

旧代码:

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?(额外的好处:为什么任务不是协变的?)。没有IAwaitable接口,但我想我可以创建一个接口,并创建一个扩展方法,将其转换为包装的、协变的、可调整的任务对象。还是我做错了?

Task<T>T中不能协变,因为它是一个类。只有接口和委托可以具有一般差异。

至于是否值得做包装。。。我想这取决于你在项目中使用协方差的程度。老实说,我怀疑随着时间的推移,你会发现所有的包装和展开都很混乱——如果只是去除协方差并不太糟糕,我会这么做的。

我认为,在ITask接口上不包括对async关键字的编译器支持是微软的一个主要疏忽。幸运的是,绕过这个限制并不太难。

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

更多信息请访问:

https://github.com/jam40jeff/ITask

相关内容

  • 没有找到相关文章

最新更新