可以/应该将任务包装在C#5.0中,等待TResult中的协变吗?

我非常喜欢使用C#5.0异步编程。 但是,有些地方更新旧代码以与TAP模型保持一致会给我带来问题。

这是其中之一 – 我不确定为什么Task在TResult中不协变,但在尝试更新协变接口以从同步模式转换为异步模式时,它会给我带来问题:

旧代码:

 public interface IInitializable // ** out generic modifier ** { ///  /// Boolean to indicate if class is ready ///  bool IsInitialized { get; } ///  /// Calls for instance to be initialized using current parameters /// Driver initialization can be done in the default constructor if desired ///  T Initialize(); } 

新代码(不会编译):

 public interface IAsyncInitializable // ** out generic modifier...broken ** { ///  /// Boolean to indicate if class is ready ///  bool IsInitialized { get; } ///  /// Calls for instance to be initialized using current parameters /// Driver initialization can be done in the default constructor if desired ///  Task InitializeAsync(); // ** breaks because Task is invariant in TResult ** } 

有没有一种合理的方法来解决这个问题而不是过于严格地修改我的API? (加分:为什么Task不协变?)。 没有IAwaitable接口,但我想我可以制作一个并创建一个扩展方法,转换为一个包装的,协变的,可用的任务对象。 或者我做错了吗?

TaskT不能协变,因为它是一个类。 只有接口和委托可以具有generics差异。

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

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

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

更多信息可在以下url找到:

https://github.com/jam40jeff/ITask