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

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

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

我也有一个带有参数的函数作为的实例,IMessage并返回一个Task。MessageResult是的实现IMessageIResult分别。

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>,等待传入的任务,然后将值转换为即可BaseC#编译器将负责其余的工作。当然,您会丢失参照身份,但是您永远都不会在课堂上得到这种身份。

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

如何从 Task<List<Derived>> 转换为 Task<List<Base>>

异步将Task <A>转换为Task <B>

无法将Task <List <TEntity >>转换为Task <IList <TEntity >>

将Task <object>转换为Task <T>,其中T未知

将Task Task集合转换为Value集合

将Long转换为Task <long>

将Task <T>强制转换为T

错误:类型不兼容:Task <Uri>无法转换为Uri

无法将类型“ void”隐式转换为“ System.Threading.Tasks.Task”

无法将类型'bool'隐式转换为'System.Threading.Tasks.Task'

无法将类型'System.Threading.Tasks.Task'隐式转换为'string'

无法将Redis.RedisValue转换为Task <T>

异步lambda,并且无法将Task.Task.List <Object>隐式转换为List <Object>

无法将类型“ System.Threading.Tasks.Task”隐式转换为“ Windows.Foundation.IAsyncAction”。存在显式转换

Task.Run()无法按预期方式工作-“无法将类型void隐式转换为对象”

无法将类型'System.Threading.Tasks.Task <Microsoft.AspNetCore.Mvc.IActionResult>'转换为'Microsoft.AspNetCore.Mvc.OkObjectResult'

无法将类型'Task <System.Collections.Generic.IEnumerable <IClass >>隐式转换为'System.Collections.Generic.IEnumerable <IClass>

无法将类型“ Microsoft.AspNetCore.Mvc.NotFoundResult”隐式转换为“ System.Threading.Tasks.Task”

无法将类型'System.Threading.tasks.task <Quartz.Scheduler>隐式转换为<Quartz.IScheduler>

ASP.NET Core Web API - 无法将类型“System.Threading.Tasks.Task<Merchant?>”隐式转换为“Merchant”

错误 CS0029:无法将类型“字符串”隐式转换为“System.Threading.Tasks.Task<string>”

从Task [Either [A,Task [B]]]转换为Task [Either [A,B]]

VB.Net Task结果自动转换为Task(of Task)

无法从 system.threding.Tasks .task<byte[]> 转换为 byte[]

无法将类型 'System.Collections.Generic.IEnumerable<System.Threading.Tasks.Task>' 隐式转换为 <System.Threading.Tasks.Task<bool>>'

如何将任务转换为Task <T>?

将'Task <IList <T >>'转换为'IList <T>'

将 foreach 循环转换为 Task.WhenAll

F#-将Task <unit>转换为普通任务