Summary
Given a run-time reference to a type (and a value of that type), how can I create a completed Task of that type with the given value?
Similar to Task.FromResult<T>(value), but where T is unknown at compile time?
Background
Not that it matters, I'm trying to create a mock implementation of IAsyncQueryProvider, by adapting some code I found here (including some changes for .NET Core 3.1 suggested in the comments by @Mandelbrotter).
Here's the relevant method:
public TResult ExecuteAsync<TResult>(Expression expression, CancellationToken cancellationToken)
{
var value = Execute(expression);
return Task.FromResult((dynamic) value);
}
Note that because this is an async method, TResult is actually always of type Task<something>. But, we can't declare the method like that because we're implementing a pre-defined interface. Nonetheless, we use Task.FromResult() to return a completed Task.
You'll notice that we don't use Task.FromResult(value) directly; we cast value to dynamic first. This is because the return value of the Execute call is declared as Object, and if we simply did Task.FromResult(value) we'd return something of type Task<Object>, which is generally not the correct type - and that causes issues further up the stack.
However, while this approach works for queries returning simple types such as int or DateTime, it fails when the query returns a nullable value. In this case, when the value returned is not null the type of value is just the underlying type, not the nullable type - and so we end up returning something of type Task<int> instead of Task<int?>.
I'd like to solve this (and do away with the use of dynamic) by explicitly creating a Task of the correct type. I can determine the desired type, either using reflection on TResult, or more conveniently by using expression.Type.
However, even once I know the type, I can't find a way to create a completed Task of that type. Task.FromResult<T> requires me to know T at compile-time. I've not been able to find a way to create a completed Task by passing in the type as a parameter.