我有一个带有委托参数的以下函数,该参数接受一个接口的类型并返回另一个接口的任务。
public void Bar(Func<IMessage, Task<IResult>> func)
{
throw new NotImplementedException();
}
我也有一个带有参数的函数作为的实例,IMessage
并返回一个Task。Message
和Result
是的实现IMessage
和IResult
分别。
private Task<Result> DoSomething(Message m) { return new Task<Result>(() => new Result()); }
将DoSomething传递给Bar时收到错误消息。
Bar(m => DoSomething((Message)m));
// Cannot convert type 'Task<Result>' to 'Task<IResult>'
为什么不Result
隐式转换成IResult
?
我想这是协方差的问题。但是,在这种情况下,Result
实现IResult
。我还尝试通过创建接口并将其标记TResult
为协变来解决协方差问题。
public interface IFoo<TMessage, out TResult>
{
void Bar(Func<TMessage, Task<TResult>> func);
}
但是我得到了错误:
无效的差异:类型参数“ TResult”必须在上始终有效
IFoo<TMessage, TResult>.Bar(Func<TMessage, Task<TResult>>)
。“ TResult”是协变的。
现在我被卡住了。我知道我在使用协方差时遇到问题,但不确定如何解决。有任何想法吗?
编辑:此问题特定于任务。我async await
在应用程序中实现时遇到了这个问题。我遇到了这个通用实现,并添加了一个Task
。其他人在这种类型的转换过程中可能会遇到相同的问题。
解决方案:以下是基于以下答案的解决方案:
Func<Task<Result>, Task<IResult>> convert = async m => await m;
Bar(m => convert(DoSomething((Message)m)));
C#不允许类的变化,仅允许使用引用类型进行参数化的接口和委托。Task<T>
是一类。
这有点不幸,因为可以将其安全协变Task<T>
的那些稀有类之一。
但是,将a转换Task<Derived>
为a是很容易的Task<Base>
。只需创建一个带aTask<Derived>
并返回的辅助方法/ lambda Task<Base>
,等待传入的任务,然后将值转换为即可Base
。C#编译器将负责其余的工作。当然,您会丢失参照身份,但是您永远都不会在课堂上得到这种身份。
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句