Consider the following interface:
public interface IProvider
{
Task<bool> Contains(string key);
}
This is implementation satisfies Visual Studio
public Task<bool> Contains(string key)
{
return Task.FromResult(false);
}
This implementation is convenient to write and would seem to achieve the same thing:
public async Task<bool> Contains(string key)
{
return false;
}
However, Visual Studio throws a hissy-fit and insists:
This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await TaskEx.Run(...)' to do CPU-bound work on a background thread.
I'd love to just ignore that warning and avoid using Task.FromResult(...).
Are there any negative consequences to using the latter option?
The reason for that "hissy fit" is that the compiler needs to do a lot of work to present a task that works in all the expected right ways here, which you can see by compiling and decompiling it
Task.FromResult is cleaner, but may still have overhead - IIRC there are some scenarios where a Task.FromResult might work efficiently here (returning the same object each time), but I wouldn't rely on it.
There are 2 pragmatic reliable approaches:
return a reused static Task<bool> result each time
use ValueTask<bool> - which seems ideal here if you are returning synchronously a lot of the time
i.e.
private readonly static Task<bool> s_False = Task.FromResult(false);
public Task<bool> Contains(string key, string scope)
{
return s_False ;
}
or
public ValueTask<bool> Contains(string key, string scope)
{
return new ValueTask<bool>(false);
}
Note: the second of these may not be possible in this case, since you didn't define the interface. But: if you ever are designing an interface that needs to allow async usage but which may actually be sync: consider using ValueTask<T> as the exchange type, not Task<T>.
The generated C# of:
public async System.Threading.Tasks.Task<bool> Contains(string key, string scope)
{
return false;
}
is something like:
[StructLayout(LayoutKind.Auto)]
[CompilerGenerated]
private struct <Contains>d__0 : IAsyncStateMachine
{
public int <>1__state;
public AsyncTaskMethodBuilder<bool> <>t__builder;
private void MoveNext()
{
bool result;
try
{
result = false;
}
catch (Exception exception)
{
<>1__state = -2;
<>t__builder.SetException(exception);
return;
}
<>1__state = -2;
<>t__builder.SetResult(result);
}
void IAsyncStateMachine.MoveNext()
{
//ILSpy generated this explicit interface implementation from .override directive in MoveNext
this.MoveNext();
}
[DebuggerHidden]
private void SetStateMachine(IAsyncStateMachine stateMachine)
{
<>t__builder.SetStateMachine(stateMachine);
}
void IAsyncStateMachine.SetStateMachine(IAsyncStateMachine stateMachine)
{
//ILSpy generated this explicit interface implementation from .override directive in SetStateMachine
this.SetStateMachine(stateMachine);
}
}
[AsyncStateMachine(typeof(<Contains>d__0))]
public Task<bool> Contains(string key, string scope)
{
<Contains>d__0 stateMachine = default(<Contains>d__0);
stateMachine.<>t__builder = AsyncTaskMethodBuilder<bool>.Create();
stateMachine.<>1__state = -1;
AsyncTaskMethodBuilder<bool> <>t__builder = stateMachine.<>t__builder;
<>t__builder.Start(ref stateMachine);
return stateMachine.<>t__builder.Task;
}
Related
There are plenty of classes in .NET standard library that have no interfaces. It ignores the dependency inversion principle. There is the same story with static methods. But we can fluently adapt them like
class DateTimeProvider : IDateTimeProvider {
public DateTime GetNow() => DateTime.Now;
}
From time to time, it is necessary to make this adaptation, especially for unit testing. I found one more reason to adapt the class to be interfaced. It is covariance. Missing covariance is painful, and the most painful example is Task<T>.The covariance type parameter can't be declared in the generic class. And the following doesn't work.
class A {}
class B : A {}
...
Task<A> a = GetBAsync();
Hmm, it looks like I need to adapt it to make it has an additional interface. But it isn't so easy as with DateTime. The extra point is that C# has async/await syntax construction that depends on Task. I don't want to lose this construction.
After some investigation, I found out that it is possible to do it by implementing some interfaces. Some of those interfaces are extensional (some specific methods/properties that are necessary to be implemented but not included in any C# interface).
So, I have declared the following interfaces (to have covariance) and implemented the following classes.
interface IAwaiter<out T> : ICriticalNotifyCompletion
{
bool IsCompleted { get; }
T GetResult();
}
struct Awaiter<T> : IAwaiter<T>
{
private readonly TaskAwaiter<T> _origin;
public Awaiter(TaskAwaiter<T> origin) =>
_origin = origin;
public bool IsCompleted =>
_origin.IsCompleted;
public T GetResult() =>
_origin.GetResult();
public void OnCompleted(Action continuation) =>
_origin.OnCompleted(continuation);
public void UnsafeOnCompleted(Action continuation) =>
_origin.UnsafeOnCompleted(continuation);
}
interface IAsyncJob<out T>
{
IAwaiter<T> GetAwaiter();
}
struct Job<T> : IAsyncJob<T>
{
private readonly Task<T> _task;
public Job(Task<T> task) =>
_task = task;
public IAwaiter<T> GetAwaiter() =>
new Awaiter<T>(_task.GetAwaiter());
}
After that await started to work with my custom type.
class A {}
class B : A {}
...
IAsyncJob<B> bJob = new Job<B>(Task.FromResult(new B()));
IAsyncJob<A> aJob = bJob;
A = await a;
Great! But the problem with async still exists.
I can't use my interface IAsyncJob<T> in the following context:
async IAsyncJob<B> GetBAsync() { ... }
I investigated it deeper and found out that we can solve the problem by implementing the extensional interface and attaching it to my task-like type with attribute. After the following changes, it started to be compilable.
public class JobBuilder<T>
{
public static JobBuilder<T> Create() => null;
public void Start<TStateMachine>(ref TStateMachine stateMachine)
where TStateMachine : IAsyncStateMachine { }
public void SetStateMachine(IAsyncStateMachine stateMachine) { }
public void SetResult(T result) { }
public void SetException(Exception exception) { }
public IAsyncJob<T> Task => default(IAsyncJob<T>);
public void AwaitOnCompleted<TAwaiter, TStateMachine>(
ref TAwaiter awaiter, ref TStateMachine stateMachine)
where TAwaiter : INotifyCompletion
where TStateMachine : IAsyncStateMachine { }
public void AwaitUnsafeOnCompleted<TAwaiter, TStateMachine>(
ref TAwaiter awaiter, ref TStateMachine stateMachine)
where TAwaiter : ICriticalNotifyCompletion
where TStateMachine : IAsyncStateMachine { }
}
[AsyncMethodBuilder(typeof(JobBuilder<>))]
public interface IAsyncJob<out T>
{
IAsyncJobAwaiter<T> GetAwaiter();
}
Obviously, my JobBuilder<T> is a stub and I need some implementation that will make my code not only compilable but workable. It should work the same as the default behavior for Task<T>.
Maybe, there is some Builder implementation that is used for Task<T> by default and I can delegate calls to it (I didn't find this implementation).
How to implement JobBuilder<T> to have the same for IAsyncJob<T> as .Net provides for Task<T>?
Note:
Of course, I have covariance when I do 'unboxing' of Task<T> with 'await'. And the following works fine:
A a = await GetBAsync();
IEnumerable<A> aCollection = await GetBCollectionAsync();
Also, it isn't a problem to do any conversions including casting at the execution level.
static async Task<TOut> Map<TIn, TOut>(
this Task<TIn> source,
Func<TIn, TOut> f) =>
Task.FromResult(f(await source));
...
var someNumber = await Task
.Run(() => 42)
.Map(x => (double)x)
.Map(x => x * 2.2);
But it is nothing when I want to have covariance in type system level (inside another interface that uses Task<T> in outputs).
The following is still covariant
public interface IJobAsyncGetter<out T>
{
IAsyncJob<T> GetAsync();
}
but
public interface ITaskAsyncGetter<out T>
{
Task<T> GetAsync();
}
is not.
It excludes covariants from solution design abilities.
And
IEnumerable<IJobAsyncGetter<B>> b = ...
IEnumerable<IJobAsyncGetter<A>> a = b;
works, but
IEnumerable<ITaskAsyncGetter<B>> b = ...
IEnumerable<ITaskAsyncGetter<A>> a = b;
doesn't.
It looks like Task<T> is one of .NET mistakes that lives with us because of backward compatibility. I see
public interface IAsyncEnumerable<out T>
is covariant and awaitable interface that works.
I am sure there was possible to provide ITask<T> in the same way. But it has not been. So, I am trying to adapt it. It isn't a local code problem for a quick solution. I am implementing a monadic async tree, and it is a core part of my framework. I need true covariance. And missing of it blocks me.
Instead of going through all this, I would recommend writing simple wrapper function for that specific problem:
// Sample classes
class Parent { }
class Child : Parent { }
public class Program
{
static async Task Main(string[] args)
{
Task<Parent> taskToGetChild = As<Child, Parent>(GetChildAsync);
// some code
var b = await taskToGetChild;
}
static async Task<Child> GetChildAsync()
{
return await Task.FromResult(new Child());
}
// Here's the method that allow you to mimic covariance.
static async Task<TOut> As<TIn, TOut>(Func<Task<TIn>> func)
where TIn : TOut
{
return (TOut)await func();
}
}
Based on the #GuruStron's comment, I found this repo that contains exactly what I was asking about. So, the default builder for Task<T> is System.Runtime.CompilerServices.AsyncTaskMethodBuilder<T>.
The adapter of the default builder can be implemented as the following
public struct JobBuilder<T>
{
private readonly AsyncTaskMethodBuilder<T> _origin;
private JobBuilder(AsyncTaskMethodBuilder<T> origin) =>
_origin = origin;
public IAsyncJob<T> Task => new Job<T>(_origin.Task);
public static Builder<T> Create() =>
new Builder<T>(AsyncTaskMethodBuilder<T>.Create());
public void Start<TStateMachine>(ref TStateMachine stateMachine)
where TStateMachine : IAsyncStateMachine =>
_origin.Start(ref stateMachine);
public void SetStateMachine(IAsyncStateMachine stateMachine) =>
_origin.SetStateMachine(stateMachine);
public void SetResult(T result) =>
_origin.SetResult(result);
public void SetException(Exception exception) =>
_origin.SetException(exception);
public void AwaitOnCompleted<TAwaiter, TStateMachine>(
ref TAwaiter awaiter, ref TStateMachine stateMachine)
where TAwaiter : INotifyCompletion
where TStateMachine : IAsyncStateMachine =>
_origin.AwaitOnCompleted(ref awaiter, ref stateMachine);
public void AwaitUnsafeOnCompleted<TAwaiter, TStateMachine>(
ref TAwaiter awaiter, ref TStateMachine stateMachine)
where TAwaiter : ICriticalNotifyCompletion
where TStateMachine : IAsyncStateMachine =>
_origin.AwaitUnsafeOnCompleted(ref awaiter, ref stateMachine);
}
Frankly I don't know how to implement what you are looking for. However, there is a easy workaround with minimal syntax. The idea is you await GetBAsync convert B to A, wrap A in a task and then return it. It is a extra-step, but a simple one:
Task<A> a = Task.Run(async () => (A)await b.GetBAsync());
That way you fully keep the async/await functionality.
You can still adapt Task<T> to a degree without having to implement a custom task-like type. IAsyncEnumerator<T> can give you a bit hint.
I'd define an interface like this:
interface IAsync<out T>
{
T Result { get; }
Task WaitAsync();
}
Implement the interface with a wrapper of Task<T>:
public class TaskWrapper<T> : IAsync<T>
{
private readonly Task<T> _task;
public TaskWrapper(Task<T> task)
{
_task = task;
}
public T Result => _task.Result;
public async Task WaitAsync()
{
await _task;
}
}
Add an extension method to complete the async action and return a Task of result:
public static class AsyncExtensions
{
public static async Task<T> GetResultAsync<T>(this IAsync<T> task)
{
await task.WaitAsync();
return task.Result;
}
}
With the above, you could do in your code:
class A { }
class B : A { }
IAsync<B> b = new TaskWrapper<B>(Task.FromResult<B>(new B()));
IAsync<A> a = b;
IEnumerable<IAsync<B>> bList = new List<IAsync<B>>();
IEnumerable<IAsync<A>> aList = bList;
A aValue = await a.GetResultAsync();
There are plenty of classes in .NET standard library that have no interfaces. It ignores the dependency inversion principle. There is the same story with static methods. But we can fluently adapt them like
class DateTimeProvider : IDateTimeProvider {
public DateTime GetNow() => DateTime.Now;
}
From time to time, it is necessary to make this adaptation, especially for unit testing. I found one more reason to adapt the class to be interfaced. It is covariance. Missing covariance is painful, and the most painful example is Task<T>.The covariance type parameter can't be declared in the generic class. And the following doesn't work.
class A {}
class B : A {}
...
Task<A> a = GetBAsync();
Hmm, it looks like I need to adapt it to make it has an additional interface. But it isn't so easy as with DateTime. The extra point is that C# has async/await syntax construction that depends on Task. I don't want to lose this construction.
After some investigation, I found out that it is possible to do it by implementing some interfaces. Some of those interfaces are extensional (some specific methods/properties that are necessary to be implemented but not included in any C# interface).
So, I have declared the following interfaces (to have covariance) and implemented the following classes.
interface IAwaiter<out T> : ICriticalNotifyCompletion
{
bool IsCompleted { get; }
T GetResult();
}
struct Awaiter<T> : IAwaiter<T>
{
private readonly TaskAwaiter<T> _origin;
public Awaiter(TaskAwaiter<T> origin) =>
_origin = origin;
public bool IsCompleted =>
_origin.IsCompleted;
public T GetResult() =>
_origin.GetResult();
public void OnCompleted(Action continuation) =>
_origin.OnCompleted(continuation);
public void UnsafeOnCompleted(Action continuation) =>
_origin.UnsafeOnCompleted(continuation);
}
interface IAsyncJob<out T>
{
IAwaiter<T> GetAwaiter();
}
struct Job<T> : IAsyncJob<T>
{
private readonly Task<T> _task;
public Job(Task<T> task) =>
_task = task;
public IAwaiter<T> GetAwaiter() =>
new Awaiter<T>(_task.GetAwaiter());
}
After that await started to work with my custom type.
class A {}
class B : A {}
...
IAsyncJob<B> bJob = new Job<B>(Task.FromResult(new B()));
IAsyncJob<A> aJob = bJob;
A = await a;
Great! But the problem with async still exists.
I can't use my interface IAsyncJob<T> in the following context:
async IAsyncJob<B> GetBAsync() { ... }
I investigated it deeper and found out that we can solve the problem by implementing the extensional interface and attaching it to my task-like type with attribute. After the following changes, it started to be compilable.
public class JobBuilder<T>
{
public static JobBuilder<T> Create() => null;
public void Start<TStateMachine>(ref TStateMachine stateMachine)
where TStateMachine : IAsyncStateMachine { }
public void SetStateMachine(IAsyncStateMachine stateMachine) { }
public void SetResult(T result) { }
public void SetException(Exception exception) { }
public IAsyncJob<T> Task => default(IAsyncJob<T>);
public void AwaitOnCompleted<TAwaiter, TStateMachine>(
ref TAwaiter awaiter, ref TStateMachine stateMachine)
where TAwaiter : INotifyCompletion
where TStateMachine : IAsyncStateMachine { }
public void AwaitUnsafeOnCompleted<TAwaiter, TStateMachine>(
ref TAwaiter awaiter, ref TStateMachine stateMachine)
where TAwaiter : ICriticalNotifyCompletion
where TStateMachine : IAsyncStateMachine { }
}
[AsyncMethodBuilder(typeof(JobBuilder<>))]
public interface IAsyncJob<out T>
{
IAsyncJobAwaiter<T> GetAwaiter();
}
Obviously, my JobBuilder<T> is a stub and I need some implementation that will make my code not only compilable but workable. It should work the same as the default behavior for Task<T>.
Maybe, there is some Builder implementation that is used for Task<T> by default and I can delegate calls to it (I didn't find this implementation).
How to implement JobBuilder<T> to have the same for IAsyncJob<T> as .Net provides for Task<T>?
Note:
Of course, I have covariance when I do 'unboxing' of Task<T> with 'await'. And the following works fine:
A a = await GetBAsync();
IEnumerable<A> aCollection = await GetBCollectionAsync();
Also, it isn't a problem to do any conversions including casting at the execution level.
static async Task<TOut> Map<TIn, TOut>(
this Task<TIn> source,
Func<TIn, TOut> f) =>
Task.FromResult(f(await source));
...
var someNumber = await Task
.Run(() => 42)
.Map(x => (double)x)
.Map(x => x * 2.2);
But it is nothing when I want to have covariance in type system level (inside another interface that uses Task<T> in outputs).
The following is still covariant
public interface IJobAsyncGetter<out T>
{
IAsyncJob<T> GetAsync();
}
but
public interface ITaskAsyncGetter<out T>
{
Task<T> GetAsync();
}
is not.
It excludes covariants from solution design abilities.
And
IEnumerable<IJobAsyncGetter<B>> b = ...
IEnumerable<IJobAsyncGetter<A>> a = b;
works, but
IEnumerable<ITaskAsyncGetter<B>> b = ...
IEnumerable<ITaskAsyncGetter<A>> a = b;
doesn't.
It looks like Task<T> is one of .NET mistakes that lives with us because of backward compatibility. I see
public interface IAsyncEnumerable<out T>
is covariant and awaitable interface that works.
I am sure there was possible to provide ITask<T> in the same way. But it has not been. So, I am trying to adapt it. It isn't a local code problem for a quick solution. I am implementing a monadic async tree, and it is a core part of my framework. I need true covariance. And missing of it blocks me.
Instead of going through all this, I would recommend writing simple wrapper function for that specific problem:
// Sample classes
class Parent { }
class Child : Parent { }
public class Program
{
static async Task Main(string[] args)
{
Task<Parent> taskToGetChild = As<Child, Parent>(GetChildAsync);
// some code
var b = await taskToGetChild;
}
static async Task<Child> GetChildAsync()
{
return await Task.FromResult(new Child());
}
// Here's the method that allow you to mimic covariance.
static async Task<TOut> As<TIn, TOut>(Func<Task<TIn>> func)
where TIn : TOut
{
return (TOut)await func();
}
}
Based on the #GuruStron's comment, I found this repo that contains exactly what I was asking about. So, the default builder for Task<T> is System.Runtime.CompilerServices.AsyncTaskMethodBuilder<T>.
The adapter of the default builder can be implemented as the following
public struct JobBuilder<T>
{
private readonly AsyncTaskMethodBuilder<T> _origin;
private JobBuilder(AsyncTaskMethodBuilder<T> origin) =>
_origin = origin;
public IAsyncJob<T> Task => new Job<T>(_origin.Task);
public static Builder<T> Create() =>
new Builder<T>(AsyncTaskMethodBuilder<T>.Create());
public void Start<TStateMachine>(ref TStateMachine stateMachine)
where TStateMachine : IAsyncStateMachine =>
_origin.Start(ref stateMachine);
public void SetStateMachine(IAsyncStateMachine stateMachine) =>
_origin.SetStateMachine(stateMachine);
public void SetResult(T result) =>
_origin.SetResult(result);
public void SetException(Exception exception) =>
_origin.SetException(exception);
public void AwaitOnCompleted<TAwaiter, TStateMachine>(
ref TAwaiter awaiter, ref TStateMachine stateMachine)
where TAwaiter : INotifyCompletion
where TStateMachine : IAsyncStateMachine =>
_origin.AwaitOnCompleted(ref awaiter, ref stateMachine);
public void AwaitUnsafeOnCompleted<TAwaiter, TStateMachine>(
ref TAwaiter awaiter, ref TStateMachine stateMachine)
where TAwaiter : ICriticalNotifyCompletion
where TStateMachine : IAsyncStateMachine =>
_origin.AwaitUnsafeOnCompleted(ref awaiter, ref stateMachine);
}
Frankly I don't know how to implement what you are looking for. However, there is a easy workaround with minimal syntax. The idea is you await GetBAsync convert B to A, wrap A in a task and then return it. It is a extra-step, but a simple one:
Task<A> a = Task.Run(async () => (A)await b.GetBAsync());
That way you fully keep the async/await functionality.
You can still adapt Task<T> to a degree without having to implement a custom task-like type. IAsyncEnumerator<T> can give you a bit hint.
I'd define an interface like this:
interface IAsync<out T>
{
T Result { get; }
Task WaitAsync();
}
Implement the interface with a wrapper of Task<T>:
public class TaskWrapper<T> : IAsync<T>
{
private readonly Task<T> _task;
public TaskWrapper(Task<T> task)
{
_task = task;
}
public T Result => _task.Result;
public async Task WaitAsync()
{
await _task;
}
}
Add an extension method to complete the async action and return a Task of result:
public static class AsyncExtensions
{
public static async Task<T> GetResultAsync<T>(this IAsync<T> task)
{
await task.WaitAsync();
return task.Result;
}
}
With the above, you could do in your code:
class A { }
class B : A { }
IAsync<B> b = new TaskWrapper<B>(Task.FromResult<B>(new B()));
IAsync<A> a = b;
IEnumerable<IAsync<B>> bList = new List<IAsync<B>>();
IEnumerable<IAsync<A>> aList = bList;
A aValue = await a.GetResultAsync();
Consider the following sample code
public static class TestClass
{
static async TaskWrapper<int> Test()
{
var task = Task.FromResult(4);
return await new TaskWrapper<int>(task);
}
}
public class TaskWrapper<T>
{
private readonly Task<T> _thing;
public TaskAwaiter<T> GetAwaiter() => _thing.GetAwaiter();
public TaskWrapper(Task<T> thing)
{
_thing = thing;
}
}
The compiler reports the following error on the Test() function: error CS1983: The return type of an async method must be void, Task, Task<T>, a task-like type, IAsyncEnumerable<T>, or IAsyncEnumerator<T>.
Why is this the case? The TaskWrapper type implements the GetAwaiter() method by deferring to the wrapped task type. As a matter of fact, the following test function compiles just fine, demonstrating that TaskWrapper is indeed awaitable:
static async Task Test()
{
var task = Task.FromResult(4);
_ = await new TaskWrapper<int>(task);
}
Starting from C# 7.2, the compiler supports task-like types. A task type is a class or struct with an associated builder type, identified with the AsyncMethodBuilderAttribute. Example:
[AsyncMethodBuilder(typeof(TaskWrapperMethodBuilder<>))]
public class TaskWrapper<T>
{
//...
}
The builder type is a class or struct that corresponds to the specific task type. The builder type should have the following public methods:
class TaskWrapperMethodBuilder<T>
{
public static TaskWrapperMethodBuilder<T> Create();
public void Start<TStateMachine>(ref TStateMachine stateMachine)
where TStateMachine : IAsyncStateMachine;
public void SetStateMachine(IAsyncStateMachine stateMachine);
public void SetException(Exception exception);
public void SetResult(T result);
public void AwaitOnCompleted<TAwaiter, TStateMachine>(
ref TAwaiter awaiter, ref TStateMachine stateMachine)
where TAwaiter : INotifyCompletion
where TStateMachine : IAsyncStateMachine;
public void AwaitUnsafeOnCompleted<TAwaiter, TStateMachine>(
ref TAwaiter awaiter, ref TStateMachine stateMachine)
where TAwaiter : ICriticalNotifyCompletion
where TStateMachine : IAsyncStateMachine;
public TaskWrapper<T> Task { get; }
}
With this infrastructure in place, you can then write asynchronous methods that return the TaskWrapper<T> type.
Reference:
Extending the async methods in C# - Task-like types
Async Task Types in C#
And here is an actual implementation of a task-like type, that does something useful:
PooledTaskT.cs
PooledTaskMethodBuilderT.cs
An async method must return a Task. If you want to return something else, find a way to avoid marking the method async. For example, this should work:
public static class TestClass
{
static TaskWrapper<int> Test()
{
var task = Task.FromResult(4);
return new TaskWrapper<int>(task);
}
}
So I was trying to make a simple awaitable struct that allow my to return a bool:
// define a special container for returning results
public struct BoolResult {
public bool Value;
public BoolAwaiter GetAwaiter () {
return new BoolAwaiter(Value);
}
}
// make the interface task-like
public readonly struct BoolAwaiter : INotifyCompletion {
private readonly bool _Input;
// wrap the async operation
public BoolAwaiter (bool value) {
_Input = value;
}
// is task already done (yes)
public bool IsCompleted {
get { return true; }
}
// wait until task is done (never called)
public void OnCompleted (Action continuation) => continuation?.Invoke();
// return the result
public bool GetResult () {
return _Input;
}
}
And I was using it like:
private async BoolResult LoadAssets (string label) {
//
// some await asyncFunction here
//
// then at the end
return new BoolResult { Value = true };
}
But I still get this compile error:
error CS1983: The return type of an async method must be void, Task or Task<T>
I thought my BoolResult was already Task-like? What's the issue here?
I have static class full of extension methods where each of the methods is asynchronous and returns some value - like this:
public static class MyContextExtensions{
public static async Task<bool> SomeFunction(this DbContext myContext){
bool output = false;
//...doing stuff with myContext
return output;
}
public static async Task<List<string>> SomeOtherFunction(this DbContext myContext){
List<string> output = new List<string>();
//...doing stuff with myContext
return output;
}
}
My goal is to be able to invoke any of these methods from a single method in another class and return their result as an object. It would look something like this:
public class MyHub: Hub{
public async Task<object> InvokeContextExtension(string methodName){
using(var context = new DbContext()){
//This fails because of invalid cast
return await (Task<object>)typeof(MyContextExtensions).GetMethod(methodName).Invoke(null, context);
}
}
}
The problem is that the cast fails. My dilemma is that I cannot pass any type parameters to the "InvokeContextExtension" method because it is part of a SignalR hub and is invoked by javascript. And to a certain extent I don't care about the return type of the extension method because it is just going to get serialized to JSON and sent back to the javascript client. However I do have to cast the value returned by Invoke as a Task in order to use the await operator. And I have to supply a generic parameter with that "Task" otherwise it will treat the return type as void. So it all comes down to how do I successfully cast Task with generic parameter T to a Task with a generic parameter of object where T represents the output of the extension method.
You can do it in two steps - await the task using the base class, then harvest the result using reflection or dynamic:
using(var context = new DbContext()) {
// Get the task
Task task = (Task)typeof(MyContextExtensions).GetMethod(methodName).Invoke(null, context);
// Make sure it runs to completion
await task.ConfigureAwait(false);
// Harvest the result
return (object)((dynamic)task).Result;
}
Here is a complete running example that puts in context the above technique of calling Task through reflection:
class MainClass {
public static void Main(string[] args) {
var t1 = Task.Run(async () => Console.WriteLine(await Bar("Foo1")));
var t2 = Task.Run(async () => Console.WriteLine(await Bar("Foo2")));
Task.WaitAll(t1, t2);
}
public static async Task<object> Bar(string name) {
Task t = (Task)typeof(MainClass).GetMethod(name).Invoke(null, new object[] { "bar" });
await t.ConfigureAwait(false);
return (object)((dynamic)t).Result;
}
public static Task<string> Foo1(string s) {
return Task.FromResult("hello");
}
public static Task<bool> Foo2(string s) {
return Task.FromResult(true);
}
}
In general, to convert a Task<T> to Task<object>, I would simply go for the straightforward continuation mapping :
Task<T> yourTaskT;
// ....
Task<object> yourTaskObject = yourTaskT.ContinueWith(t => (object) t.Result);
(documentation link here)
However, your actual specific need is to invoke a Task by reflection and obtain its (unknown type) result .
For this, you can refer to the complete dasblinkenlight's answer, which should fit your exact problem.
I'd like to provide an implementation which is IMHO the best combination of the earlier answers:
precise argument handling
no dynamic dispatch
general purpose extension method
Here you go:
/// <summary>
/// Casts a <see cref="Task"/> to a <see cref="Task{TResult}"/>.
/// This method will throw an <see cref="InvalidCastException"/> if the specified task
/// returns a value which is not identity-convertible to <typeparamref name="T"/>.
/// </summary>
public static async Task<T> Cast<T>(this Task task)
{
if (task == null)
throw new ArgumentNullException(nameof(task));
if (!task.GetType().IsGenericType || task.GetType().GetGenericTypeDefinition() != typeof(Task<>))
throw new ArgumentException("An argument of type 'System.Threading.Tasks.Task`1' was expected");
await task.ConfigureAwait(false);
object result = task.GetType().GetProperty(nameof(Task<object>.Result)).GetValue(task);
return (T)result;
}
You cannot cast Task<T> to Task<object>, because Task<T> is not covariant (it's not contravariant, either). The simplest solution would be to use some more reflection:
var task = (Task) mi.Invoke (obj, null) ;
var result = task.GetType ().GetProperty ("Result").GetValue (task) ;
This is slow and inefficient, but usable if this code is not executed often. As an aside, what is the use of having an asynchronous MakeMyClass1 method if you are going to block waiting for its result?
and Another possibility is to write an extension method to this purpose:
public static Task<object> Convert<T>(this Task<T> task)
{
TaskCompletionSource<object> res = new TaskCompletionSource<object>();
return task.ContinueWith(t =>
{
if (t.IsCanceled)
{
res.TrySetCanceled();
}
else if (t.IsFaulted)
{
res.TrySetException(t.Exception);
}
else
{
res.TrySetResult(t.Result);
}
return res.Task;
}
, TaskContinuationOptions.ExecuteSynchronously).Unwrap();
}
It is none-blocking solution and will preserve original state/exception of the Task.
The most efficient approach would be custom awaiter:
struct TaskCast<TSource, TDestination>
where TSource : TDestination
{
readonly Task<TSource> task;
public TaskCast(Task<TSource> task)
{
this.task = task;
}
public Awaiter GetAwaiter() => new Awaiter(task);
public struct Awaiter
: System.Runtime.CompilerServices.INotifyCompletion
{
System.Runtime.CompilerServices.TaskAwaiter<TSource> awaiter;
public Awaiter(Task<TSource> task)
{
awaiter = task.GetAwaiter();
}
public bool IsCompleted => awaiter.IsCompleted;
public TDestination GetResult() => awaiter.GetResult();
public void OnCompleted(Action continuation) => awaiter.OnCompleted(continuation);
}
}
with the following usage:
Task<...> someTask = ...;
await TaskCast<..., object>(someTask);
The limitation of this approach is that the result is not a Task<object> but an awaitable object.
I made a little extension method based on dasblinkenlight's answer:
public static class TaskExtension
{
public async static Task<T> Cast<T>(this Task task)
{
if (!task.GetType().IsGenericType) throw new InvalidOperationException();
await task.ConfigureAwait(false);
// Harvest the result. Ugly but works
return (T)((dynamic)task).Result;
}
}
Usage:
Task<Foo> task = ...
Task<object> = task.Cast<object>();
This way you can change T in Task<T> to anything you want.
For the best approach, without using reflection and dynamic ugly syntax, and without passing generic types. I would use two extension methods for achieving this goal.
public static async Task<object> CastToObject<T>([NotNull] this Task<T> task)
{
return await task.ConfigureAwait(false);
}
public static async Task<TResult> Cast<TResult>([NotNull] this Task<object> task)
{
return (TResult) await task.ConfigureAwait(false);
}
Usage:
Task<T1> task ...
Task<T2> task2 = task.CastToObject().Cast<T2>();
This my second approach, but not recommended:
public static async Task<TResult> Cast<TSource, TResult>([NotNull] this Task<TSource> task, TResult dummy = default)
{
return (TResult)(object) await task.ConfigureAwait(false);
}
Usage:
Task<T1> task ...
Task<T2> task2 = task.Cast((T2) default);
// Or
Task<T2> task2 = task.Cast<T1, T2>();
This my third approach, but not recommended: (similar to second one)
public static async Task<TResult> Cast<TSource, TResult>([NotNull] this Task<TSource> task, Type<TResult> type = null)
{
return (TResult)(object) await task.ConfigureAwait(false);
}
// Dummy type class
public class Type<T>
{
}
public static class TypeExtension
{
public static Type<T> ToGeneric<T>(this T source)
{
return new Type<T>();
}
}
Usage:
Task<T1> task ...
Task<T2> task2 = task.Cast(typeof(T2).ToGeneric());
// Or
Task<T2> task2 = task.Cast<T1, T2>();
This is not a good idea to mix await with dynamic/reflection invoke since await is a compiler instruction that generates a lot of code around invoked method and there is no real sense to "emulate" compiler work with more reflections, continuations, wrappers and etc.
Since what you need is to manage your code at RUN TIME then forget the asyc await syntax sugar which works at compile time. Rewrite SomeFunction and SomeOtherFunction without them, and start operations in your own tasks created at run time. You will get the same behavior but with crystal clear code.