c# - 无法将类型 'Task<Derived>' 转换为 'Task<Interface>'

标签 c#

我有以下带有委托(delegate)参数的函数,它接受一个接口(interface)的类型并返回另一个接口(interface)的任务。

public void Bar(Func<IMessage, Task<IResult>> func)
{
    throw new NotImplementedException();
}

我还有一个带有参数的函数作为 IMessage 的实例并返回一个任务。 MessageResultIMessage 的实现和 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/

相关文章:

c# - 通过反射获取当前的MethodBase

c# - 尝试导入非托管 dll 时 Pinvoke "System.AccessViolationException"

c# - Entity Framework - db.SaveChanges() 错误

c# - Visual Studio 2013 和 Update 2(间歇性构建错误)

c# - 从csproj文件获取项目输出路径

c# - Entity Framework 连接字符串的奇怪行为

c# - 抛出异常后我必须中断吗?

c# - 编写一个扫描电子商务网站并从中提取产品图片+价格+描述的C#程序

c# - moq:使用 Setup() 时,如何确定方法参数的相等性?

c# - JSON 根节点 - 与类名称不同