C#: Use Task<> inside Tuple - c#

This would work if I remove Tuple and just using Task<bool> or Task<string>.
public async Tuple<Task<bool>, string> Test()
{
//....
return new Tuple<Task<bool>, string>(false, "a string");
}
Any idea how to make this work?

Async method should return void (bad practice) or Task or Task<T> (see Return Types section). In your case I believe it should be
public async Task<Tuple<bool, string>> Test()
{
// await ...
return Tuple.Create(false, "a string");
}

Related

Failing to write async recursive iteration function

I'm trying to write a recursion method to retrieve the parent of a object (and that parent etc). This in itself isn't a problem but the calls are async which result in the following error:
The body of '.....Recursive(string)' cannot be an iterator block because 'Task<IEnumerable>' is not an iterator interface type [...]csharp(CS1624)
The code:
private async Task<IEnumerable<string>> Recursive(string objectId)
{
var result = await GetParent(objectId);
if (result?.Length > 0)
{
yield return result;
await Recursive(objectId);
}
}
private async Task<string> GetParent(string objectId)
{
await Task.Run(() => { return $"{objectId}/parent"; });
}
I have also tried IAsyncEnumerable but that resulted in the folllowing error:
'IAsyncEnumerable' does not contain a definition for 'GetAwaiter' and no accessible extension method 'GetAwaiter' accepting a first argument of type 'IAsyncEnumerable' could be found (are you missing a using directive or an assembly reference?) [...]csharp(CS1061)
private async IAsyncEnumerable<string> Recursive(string objectId)
{
var result = await GetParent(objectId);
if (result?.Length > 0)
{
yield return result;
await Recursive(objectId);
}
}
private async Task<string> GetParent(string objectId)
{
await Task.Run(() => { return $"{objectId}/parent"; });
}
I'm going to write a while loop to get this to work. But I'm interested if this is possible at all.
Update 2:
Ok, I think I got it. Thanks guys.
private async IAsyncEnumerable<string> Recursive(string objectId)
{
var result = await GetParent(objectId);
if (result?.Length > 0)
{
yield return result;
await foreach (var r2 in Recursive(objectId))
{
yield return r2;
}
}
}
private async Task<string> GetParent(string objectId)
{
await Task.Run(() => { return $"{objectId}/parent"; });
}
The current code wouldn't compile even if it was synchronous, and the result was IEnumerable<string>. The results of Recursive are never returned. It's not possible to just return an IEnumerable from an iterator either.
This code would work. Whether it does anything useful is another matter :
private IEnumerable<string> Recursive(string objectId)
{
var result = GetParent(objectId);
if (!string.IsNullOrEmpty(result))
{
yield return result;
foreach(var r in Recursive(result))
{
yield return r;
}
}
}
private string GetParent(string objectId)
{
return $"{objectId}/parent";
}
Getting it to work asynchronously only needs changing to IAsyncEnumerable and using await:
private async IAsyncEnumerable<string> Recursive(string objectId)
{
var result = await GetParent(objectId);
if (!string.IsNullOrEmpty(result))
{
yield return result;
await foreach(var r in Recursive(result))
{
yield return r;
}
}
}
private Task<string> GetParent(string objectId)
{
return Task.FromResult($"{objectId}/parent");
}

Cast Task<T> to Task<object> in C# without having T

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.

How can I create new Task<T>( async( ) => { return new T( ); } );? [duplicate]

This question already has answers here:
Cannot convert lambda expression to type "..." because it is not a delegate type
(2 answers)
Closed 7 years ago.
I need to create a function which will return a task that will be executed at another time.
I would like for that task to return a value (preferably through awaiting it).
I would also like to be able to await methods/functions within that task.
When I try to create a simple conceptual function which should do what I want, I get a red-line error message :
private static Task<object> FooGet( ) {
return new Task<object>( async ( ) => {
await asyncBar( );
return new object( );
} );
}
The error reads : Cannot convert lambda expression to type 'object' because it is not a delegate type
As soon as I remove the async keyword from the lambda, everything's hunky dory.
How can I fix this? Can I even fix this?
I found the answer after digging a bit more. In case someone runs into this precise issue the answer already exists.
Shorthand :
private static Task<object> FooGet()
{
return new Task<object>(async () =>
{
await asyncBar();
return new object();
});
}
becomes
private static Task<object> FooGet()
{
return ((Func<Task<object>>)(async () =>
{
await asyncBar();
return new object();
}))();
}
you need to explicitly cast it to Func<Task<object>> or if you want to keep things more readable you could refactory this as
private static Task<object> FooGet( ) {
return new Task<object>(innerTask);
}
private async static Task<object> innerTask() {
await asyncBar( );
return new object( );
}
private static async Task asyncBar( ){
}

Creating async version of a generic method

I have this generic method for Deserializing a type
public static T Deserialize<T>(string xmlString)
{
if (string.IsNullOrWhiteSpace(xmlString))
return default(T);
using (MemoryStream memStream = new MemoryStream(Encoding.Unicode.GetBytes(xmlString)))
{
memStream.Position = 0;
System.Xml.Serialization.XmlSerializer serializer = new System.Xml.Serialization.XmlSerializer(typeof(T));
return (T)serializer.Deserialize(memStream);
}
}
Now I wish to make an async version which I tried like this.
public static Task DeserializeAsync(string xmlString)
{
return Task.Run(() =>
{
Deserialize(xmlString));
});
}
Obviously the async method has syntax errors because I am missing T.
I also tried this and I get errors.
public static Task<T> DeserializeAsync(string xmlString)
{
return Task.Run(() =>
{
Deserialize<T>(xmlString));
});
}
Can anyone show me the correct way of writing the async method?
You are just forgetting to declare your method as generic (note the <T>), and actually return the result of Deserialize:
public static Task<T> DeserializeAsync<T>(string xmlString)
{
return Task.Run(() =>
{
return Deserialize<T>(xmlString));
});
}
or more simply:
public static Task<T> DeserializeAsync<T>(string xmlString)
{
return Task.Run(() => Deserialize<T>(xmlString)));
}

how to return method which has task<t> return type

public override Task<IdentityResult> ValidateAsync(AppUser item)
{
if(item.Email != "a#a.com")
{
IEnumerable<string> errors = new List<string>() { "error1" };
}
}
The IdentityResultjust needs a simple array or ienumerable of strings in its constructor.
Whats the correct syntax?
If you absolutely need to have ValidateAsync() instead of just Validate(), use a TaskCompletionSource to simulate.
public override Task<IdentityResult> ValidateAsync(AppUser item)
{
var result = new IdentityResult();
var tcs = new TaskCompletionSource<IdentityResult>();
if(item.Email != "a#a.com")
{
IEnumerable<string> errors = new List<string>() { "error1" };
result.Add(errors)
}
tcs.SetResult(result);
return tcs.Task;
}
Using Task.Run creates unnecessary overhead.
EDIT: I'm not exactly sure if TaskCompletionSource is any better than Task.Run. I'd love to hear the answer.
You could use Task.Run() to start and get a reference to a new Task:
public IdentityResult Validate( AppUser item )
{
IdentityResult result;
// do stuff
return result;
}
public override Task<IdentityResult> ValidateAsync( AppUser item )
{
return Task.Run( () => Validate(item) );
}

Categories

Resources