我有以下带有委托(delegate)参数的函数,它接受一个接口(interface)的类型并返回另一个接口(interface)的任务。
public void Bar(Func<IMessage, Task<IResult>> func)
{
throw new NotImplementedException();
}
我还有一个带有参数的函数作为 IMessage
的实例并返回一个任务。 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
.我还尝试通过创建接口(interface)并标记 TResult
来解决协方差问题。作为协变。
public interface IFoo<TMessage, out TResult>
{
void Bar(Func<TMessage, Task<TResult>> func);
}
但是我得到了错误:
Invalid variance: The type parameter 'TResult' must be invariantly valid on
IFoo<TMessage, TResult>.Bar(Func<TMessage, Task<TResult>>)
. 'TResult' is covariant.
现在我卡住了。我知道我有协方差问题,但我不确定如何解决它。有什么想法吗?
编辑:此问题特定于任务。我通过实现 async await
遇到了这个问题在我的申请中。我遇到了这个通用实现并添加了一个 Task
.在这种类型的转换过程中,其他人可能会遇到同样的问题。
解决方案:这是基于以下答案的解决方案:
Func<Task<Result>, Task<IResult>> convert = async m => await m;
Bar(m => convert(DoSomething((Message)m)));
最佳答案
C# 不允许类的变化,只允许使用引用类型参数化的接口(interface)和委托(delegate)。 Task<T>
是一个类。
这有点不幸,因为 Task<T>
是那些可以安全协变的稀有类之一。
然而,转换 Task<Derived>
很容易到 Task<Base>
.只需制作一个带有 Task<Derived>
的辅助方法/lambda并返回 Task<Base>
,等待传入的任务,并返回转换为Base
的值. C# 编译器会处理剩下的事情。当然,您会失去引用身份,但您永远不会通过类(class)获得它。
关于c# - 无法将类型 'Task<Derived>' 转换为 'Task<Interface>',我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37818642/