Cannot convert type 'Task' to 'Task'

后端 未结 3 1368
忘掉有多难
忘掉有多难 2020-12-03 10:49

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

        
相关标签:
3条回答
  • 2020-12-03 11:38

    It seems like there's got to be a cleaner way of doing this, but it is possible to create a wrapping task of the correct type. I introduced a new function called GeneralizeTask().

    Task<TBase> GeneralizeTask<TBase, TDerived>(Task<TDerived> task) 
        where TDerived : TBase 
    {
        var newTask = new Task<TBase>(() => {
            if (task.Status == TaskStatus.Created) task.Start();
            task.Wait();
            return (TBase)task.Result;
        });
        return newTask;
    }
    

    Edit:

    As @EricLippert points out, this can be simplified significantly. I first tried to find such a way to implement this method, but couldn't find one that compiled. As it turned out, the real solution was even simpler than I imagined.

    async Task<TBase> GeneralizeTask<TBase, TDerived>(Task<TDerived> task) 
        where TDerived : TBase 
    {
        return (TBase) await task;
    }
    

    You can then invoke Bar() like this.

    Bar(m => GeneralizeTask<IResult, Result>(DoSomething((Message)m)));
    
    0 讨论(0)
  • 2020-12-03 11:38

    I am using another version of GeneralizeTask, which is stated by @Recursive, on Asp Net Core Framework. Here it is:

    public static Task<TBase> GeneralizeTask<TDerived, TBase>(this Task<TDerived> task, CancellationToken cancellationToken = default) 
     where TBase : class 
     where TDerived : TBase
    {
        var result = task.ContinueWith(t => (TBase)t.Result, cancellationToken);
        return result;
    }
    
    0 讨论(0)
  • 2020-12-03 11:42

    C# does not allow variance on classes, only interfaces and delegates that are parameterized with reference types. Task<T> is a class.

    This is somewhat unfortunate, as Task<T> is one of those rare classes that could be made safely covariant.

    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.

    0 讨论(0)
提交回复
热议问题