无法转换类型'Task< Derived>'到“任务<接口>” [英] Cannot convert type 'Task<Derived>' to 'Task<Interface>'
问题描述
我具有以下带有委托参数的函数,该参数接受一个接口的类型并返回另一个接口的任务。
I have the following function with a delegate parameter that accepts a type of one interface and returns a task of another.
public void Bar(Func<IMessage, Task<IResult>> func)
{
throw new NotImplementedException();
}
我也有一个函数,该函数的参数为<$ c $的实例c> IMessage 并返回一个任务。 Message
和 Result
是 IMessage
和<$ c的实现
I also have a function with a parameter as an instance of IMessage
and returns a Task. Message
and Result
are implementations of IMessage
and IResult
respectively.
private Task<Result> DoSomething(Message m) { return new Task<Result>(() => new Result()); }
将DoSomething传递到Bar时会收到错误消息。
I receive an error when I pass DoSomething into Bar.
Bar(m => DoSomething((Message)m));
// Cannot convert type 'Task<Result>' to 'Task<IResult>'
为什么 Result
不能隐式转换为 IResult
?
Why won't Result
implicitly convert into IResult
?
我想这是协方差问题。但是,在这种情况下, Result
实现了 IResult
。我还尝试通过创建一个接口并将 TResult
标记为协变来解决协方差问题。
I would imagine it's an issue with covariance. However, in this case, Result
implements IResult
. I've also tried to solve the covariance issue by creating an interface and marking TResult
as covariant.
public interface IFoo<TMessage, out TResult>
{
void Bar(Func<TMessage, Task<TResult>> func);
}
但是我得到了错误:
无效方差:类型参数 TResult必须始终对
IFoo< TMessage,TResult> .Bar(Func< TMessage,Task< ; TResult>>)
。
TResult是协变的。
Invalid variance: The type parameter 'TResult' must be invariantly valid on
IFoo<TMessage, TResult>.Bar(Func<TMessage, Task<TResult>>)
. 'TResult' is covariant.
现在我被困住了。我知道我在使用协方差时遇到问题,但不确定如何解决。有任何想法吗?
Now I'm stuck. I know I have an issue with covariance but I'm not sure how to solve it. Any ideas?
编辑:此问题特定于任务。我在应用程序中实现了 async await
遇到了这个问题。我遇到了这个通用实现,并添加了 Task
。其他人在这种类型的转换过程中可能会遇到相同的问题。
This question is specific to Tasks. I ran into this problem by implementing async await
in my application. I came across this generic implementation and added a Task
. Others may have the same issues during this type of conversion.
解决方案:以下是基于以下答案的解决方案:
Solution: Here's the solution based on the answers below:
Func<Task<Result>, Task<IResult>> convert = async m => await m;
Bar(m => convert(DoSomething((Message)m)));
推荐答案
C#不允许类的变化,仅接口和用引用类型参数化的委托。 Task< T>
是一个类。
C# does not allow variance on classes, only interfaces and delegates that are parameterized with reference types. Task<T>
is a class.
这有点不幸,因为 Task< T>
是可以可以安全地进行协变的那些稀有类之一。
This is somewhat unfortunate, as Task<T>
is one of those rare classes that could be made safely covariant.
但是它很容易将 Task< Derived>
转换为 Task< Base>
。只需创建一个辅助方法/ lambda,使其接受 Task< Derived>
并返回 Task< Base>
,等待通过-in任务,并将值强制转换为 Base
。 C#编译器将负责其余的工作。当然,您会失去参照身份,但是您永远都不会在课堂上得到这种身份。
However it is easy enough to convert a Task<Derived>
to a Task<Base>
. Just make a helper method / lambda that takes a Task<Derived>
and returns Task<Base>
, await the passed-in task, and return the value cast to Base
. The C# compiler will take care of the rest. Of course you lose referential identity, but you weren't ever going to get that with a class.
这篇关于无法转换类型'Task< Derived>'到“任务<接口>”的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!