I have a legacy scenario where a ref bool was being used to send a cancellation signal to an implementation. Now, I want to call a Task-based library method that takes a CancellationToken instance, which I also want to be cancelled when the boolean changes value.
This is what I have to work with:
void Method(ref bool isCancelled)
{
while (!isCancelled)
{
...
DoThis();
DoThat();
...
}
}
And this is what I want to do:
Task MethodAsync(ref bool isCancelled)
{
while (!isCancelled)
{
...
DoThis();
await DoTheNewThingAsync(isCancelled.ToCancellationToken());
DoThat();
...
}
}
ToCancellationToken() doesn't exist in this context of course, and is used just to show the intent.
I tried to create a custom implementation of CancellationTokenSource but there is nothing virtual in the class that I could work with. It's also not possible to create a custom CancellationToken directly since it is a struct and cannot be inherited.
I'm aware that using a ref bool is a poor practice but I can't currently change the underlying implementation that relies on it, so I need a way to use it's value as the cancellation mechanism for the task-based call.
It's complicated. For a few reasons:
You cannot pass a parameter by ref to an async method. You're using await, but to use await, your method needs to be marked async. And async methods cannot have ref parameters. For example, this will not compile:
async Task MethodAsync(ref bool isCancelled)
{
while (!isCancelled)
{
DoThis();
await DoTheNewThingAsync(isCancelled.ToCancellationToken());
DoThat();
}
}
That will give you the compiler error:
CS1988: Async methods cannot have ref, in or out parameters
You cannot use ref parameters in anonymous methods. I thought about using a Timer to check the variable. Something like this:
public static CancellationToken ToCancellationToken(ref bool isCancelled)
{
var tokenSource = new CancellationTokenSource();
var timer = new System.Timers.Timer()
{
AutoReset = true,
Interval = 100
};
timer.Elapsed += (source, e) =>
{
if (isCancelled)
{
tokenSource.Cancel();
timer.Dispose();
}
};
timer.Enabled = true;
return tokenSource.Token;
}
But that gives you the compiler error:
CS1628: Cannot use ref, out, or in parameter 'isCancelled' inside an anonymous method, lambda expression, query expression, or local function
I don't see any other way to get the bool into the event handler by reference.
The closest I could get is something like this:
void Method(ref bool isCancelled)
{
while (!isCancelled)
{
DoThis();
using (var tokenSource = new CancellationTokenSource()) {
var mytask = DoTheNewThingAsync(tokenSource.Token);
while (true)
{
//wait for either the task to finish, or 100ms
if (Task.WaitAny(mytask, Task.Delay(100)) == 0)
{
break; //mytask finished
}
if (isCancelled) tokenSource.Cancel();
}
// This will throw an exception if an exception happened in
// DoTheNewThingAsync. Otherwise we'd never know if it
// completed successfully or not.
mytask.GetAwaiter().GetResult();
}
DoThat();
}
}
However, that blocks the caller, so I don't entirely see how that could even be useful (how can the caller change isCancelled if it's blocked?). But that's kind of what your existing method is doing, so maybe it would work?
But this is super hacky. If you can at all control how anything is done upstream, do that instead.
I've hacked up a somewhat working solution:
public static class TaskRefBoolCancellable
{
public static T SynchronousAwait<T>(Func<CancellationToken, Task<T>> taskToRun, ref bool isCancelled)
{
using (var cts = new CancellationTokenSource())
{
var runningTask = taskToRun(cts.Token);
while (!runningTask.IsCompleted)
{
if (isCancelled)
cts.Cancel();
Thread.Sleep(100);
}
return runningTask.Result;
}
}
}
void Method(ref bool isCancelled)
{
while (!isCancelled)
{
...
DoThis();
var result = TaskRefBoolCancellable.SynchronousAwait(DoTheNewThingAsync, ref isCancelled);
DoThat();
...
}
}
WARNING: This code runs synchronously on calling thread. So there are no guarantees it will work nicely with other parts of the code, as it blocks the calling thread. Also, it polls the isCancelled variable, making it both ineffective and the cancellation is not immediate.
I would consider this a stop-gap solution as you replace the ref bool isCancelled with proper task-based cancellation.
This is an attempted improvement on Euphoric's inventive solution. Instead of Thread.Sleep, this one uses the Task.Wait overload that accepts a timeout. This way no extra delay will be imposed to the completion of the task.
public static void Wait(Func<CancellationToken, Task> taskFactory,
ref bool cancel, int pollInterval = 100)
{
using (var cts = new CancellationTokenSource())
{
if (cancel) cts.Cancel();
var task = taskFactory(cts.Token);
while (!cancel)
{
if (task.Wait(pollInterval)) return;
}
cts.Cancel();
task.Wait();
}
}
Usage example:
Wait(DoTheNewThingAsync, ref isCancelled);
If you are making a method async Task and still want to use bool semantics, you have to pass an object so that in can keep the reference to the bool value. This can be done without any blocking operations if bool parameter can be converted to Ref<bool> in client code:
public class Ref
{
public static Ref<T> Create<T>(T value) => new Ref<T>(value);
}
public class Ref<T> : Ref
{
private T value;
public Ref(T value) => Value = value;
public T Value
{
get => value;
set
{
this.value = value;
OnChanged?.Invoke(value);
}
}
public override string ToString() => Value?.ToString() ?? "";
public static implicit operator T(Ref<T> r) => r.Value;
public event Action<T> OnChanged;
}
public static class RefExtensions
{
public static CancellationToken ToCancellationToken(this Ref<bool> cancelled)
{
var cts = new CancellationTokenSource();
cancelled.OnChanged += value => { if (value) cts.Cancel(); };
return cts.Token;
}
}
public async Task Method(Ref<bool> isCancelled)
{
var cancellationToken = isCancelled.ToCancellationToken();
while(!isCancelled)
{
...
DoThis();
await DoTheNewThingAsync(cancellationToken);
DoThat();
...
}
}
public class Tests
{
[Fact]
public async Task Fact()
{
var cancelled = Ref.Create(false);
Task.Run(async () =>
{
await Task.Delay(500);
cancelled.Value = true;
});
var task = Method(cancelled);
await Task.Delay(1000);
task.Status.Should().Be(TaskStatus.RanToCompletion);
}
}
Related
I want to write an async method with an out parameter, like this:
public async void Method1()
{
int op;
int result = await GetDataTaskAsync(out op);
}
How do I do this in GetDataTaskAsync?
You can't have async methods with ref or out parameters.
Lucian Wischik explains why this is not possible on this MSDN thread: http://social.msdn.microsoft.com/Forums/en-US/d2f48a52-e35a-4948-844d-828a1a6deb74/why-async-methods-cannot-have-ref-or-out-parameters
As for why async methods don't support out-by-reference parameters?
(or ref parameters?) That's a limitation of the CLR. We chose to
implement async methods in a similar way to iterator methods -- i.e.
through the compiler transforming the method into a
state-machine-object. The CLR has no safe way to store the address of
an "out parameter" or "reference parameter" as a field of an object.
The only way to have supported out-by-reference parameters would be if
the async feature were done by a low-level CLR rewrite instead of a
compiler-rewrite. We examined that approach, and it had a lot going
for it, but it would ultimately have been so costly that it'd never
have happened.
A typical workaround for this situation is to have the async method return a Tuple instead.
You could re-write your method as such:
public async Task Method1()
{
var tuple = await GetDataTaskAsync();
int op = tuple.Item1;
int result = tuple.Item2;
}
public async Task<Tuple<int, int>> GetDataTaskAsync()
{
//...
return new Tuple<int, int>(1, 2);
}
The C#7+ Solution is to use implicit tuple syntax.
private async Task<(bool IsSuccess, IActionResult Result)> TryLogin(OpenIdConnectRequest request)
{
return (true, BadRequest(new OpenIdErrorResponse
{
Error = OpenIdConnectConstants.Errors.AccessDenied,
ErrorDescription = "Access token provided is not valid."
}));
}
return result utilizes the method signature defined property names. e.g:
var foo = await TryLogin(request);
if (foo.IsSuccess)
return foo.Result;
You cannot have ref or out parameters in async methods (as was already noted).
This screams for some modelling in the data moving around:
public class Data
{
public int Op {get; set;}
public int Result {get; set;}
}
public async void Method1()
{
Data data = await GetDataTaskAsync();
// use data.Op and data.Result from here on
}
public async Task<Data> GetDataTaskAsync()
{
var returnValue = new Data();
// Fill up returnValue
return returnValue;
}
You gain the ability to reuse your code more easily, plus it's way more readable than variables or tuples.
I had the same problem as I like using the Try-method-pattern which basically seems to be incompatible to the async-await-paradigm...
Important to me is that I can call the Try-method within a single if-clause and do not have to pre-define the out-variables before, but can do it in-line like in the following example:
if (TryReceive(out string msg))
{
// use msg
}
So I came up with the following solutions:
Note: The new solution is superior, because it can be used with methods that simply return a tuple as described in many of the other answers here, what might often be found in existing code!
New solution:
Create extension methods for ValueTuples:
public static class TupleExtensions
{
public static bool TryOut<P2>(this ValueTuple<bool, P2> tuple, out P2 p2)
{
bool p1;
(p1, p2) = tuple;
return p1;
}
public static bool TryOut<P2, P3>(this ValueTuple<bool, P2, P3> tuple, out P2 p2, out P3 p3)
{
bool p1;
(p1, p2, p3) = tuple;
return p1;
}
// continue to support larger tuples...
}
Define async Try-method like this:
public async Task<(bool, string)> TryReceiveAsync()
{
string message;
bool success;
// ...
return (success, message);
}
Call the async Try-method like this:
if ((await TryReceiveAsync()).TryOut(out string msg))
{
// use msg
}
Old solution:
Define a helper struct:
public struct AsyncOut<T, OUT>
{
private readonly T returnValue;
private readonly OUT result;
public AsyncOut(T returnValue, OUT result)
{
this.returnValue = returnValue;
this.result = result;
}
public T Out(out OUT result)
{
result = this.result;
return returnValue;
}
public T ReturnValue => returnValue;
public static implicit operator AsyncOut<T, OUT>((T returnValue ,OUT result) tuple) =>
new AsyncOut<T, OUT>(tuple.returnValue, tuple.result);
}
Define async Try-method like this:
public async Task<AsyncOut<bool, string>> TryReceiveAsync()
{
string message;
bool success;
// ...
return (success, message);
}
Call the async Try-method like this:
if ((await TryReceiveAsync()).Out(out string msg))
{
// use msg
}
For multiple out parameters you can define additional structs (e.g. AsyncOut<T,OUT1, OUT2>) or you can return a tuple.
Alex made a great point on readability. Equivalently, a function is also interface enough to define the type(s) being returned and you also get meaningful variable names.
delegate void OpDelegate(int op);
Task<bool> GetDataTaskAsync(OpDelegate callback)
{
bool canGetData = true;
if (canGetData) callback(5);
return Task.FromResult(canGetData);
}
Callers provide a lambda (or a named function) and intellisense helps by copying the variable name(s) from the delegate.
int myOp;
bool result = await GetDataTaskAsync(op => myOp = op);
This particular approach is like a "Try" method where myOp is set if the method result is true. Otherwise, you don't care about myOp.
I love the Try pattern. It's a tidy pattern.
if (double.TryParse(name, out var result))
{
// handle success
}
else
{
// handle error
}
But, it's challenging with async. That doesn't mean we don't have real options. Here are the three core approaches you can consider for async methods in a quasi-version of the Try pattern.
Approach 1 - output a structure
This looks most like a sync Try method only returning a tuple instead of a bool with an out parameter, which we all know is not permitted in C#.
var result = await DoAsync(name);
if (result.Success)
{
// handle success
}
else
{
// handle error
}
With a method that returns true of false and never throws an exception.
Remember, throwing an exception in a Try method breaks the whole purpose of the pattern.
async Task<(bool Success, StorageFile File, Exception exception)> DoAsync(string fileName)
{
try
{
var folder = ApplicationData.Current.LocalCacheFolder;
return (true, await folder.GetFileAsync(fileName), null);
}
catch (Exception exception)
{
return (false, null, exception);
}
}
Approach 2 - pass in callback methods
We can use anonymous methods to set external variables. It's clever syntax, though slightly complicated. In small doses, it's fine.
var file = default(StorageFile);
var exception = default(Exception);
if (await DoAsync(name, x => file = x, x => exception = x))
{
// handle success
}
else
{
// handle failure
}
The method obeys the basics of the Try pattern but sets out parameters to passed in callback methods. It's done like this.
async Task<bool> DoAsync(string fileName, Action<StorageFile> file, Action<Exception> error)
{
try
{
var folder = ApplicationData.Current.LocalCacheFolder;
file?.Invoke(await folder.GetFileAsync(fileName));
return true;
}
catch (Exception exception)
{
error?.Invoke(exception);
return false;
}
}
There's a question in my mind about performance here. But, the C# compiler is so freaking smart, that I think you're safe choosing this option, almost for sure.
Approach 3 - use ContinueWith
What if you just use the TPL as designed? No tuples. The idea here is that we use exceptions to redirect ContinueWith to two different paths.
await DoAsync(name).ContinueWith(task =>
{
if (task.Exception != null)
{
// handle fail
}
if (task.Result is StorageFile sf)
{
// handle success
}
});
With a method that throws an exception when there is any kind of failure. That's different than returning a boolean. It's a way to communicate with the TPL.
async Task<StorageFile> DoAsync(string fileName)
{
var folder = ApplicationData.Current.LocalCacheFolder;
return await folder.GetFileAsync(fileName);
}
In the code above, if the file is not found, an exception is thrown. This will invoke the failure ContinueWith that will handle Task.Exception in its logic block. Neat, huh?
Listen, there's a reason we love the Try pattern. It's fundamentally so neat and readable and, as a result, maintainable. As you choose your approach, watchdog for readability. Remember the next developer who in 6 months and doesn't have you to answer clarifying questions. Your code can be the only documentation a developer will ever have.
Best of luck.
One nice feature of out parameters is that they can be used to return data even when a function throws an exception. I think the closest equivalent to doing this with an async method would be using a new object to hold the data that both the async method and caller can refer to. Another way would be to pass a delegate as suggested in another answer.
Note that neither of these techniques will have any of the sort of enforcement from the compiler that out has. I.e., the compiler won’t require you to set the value on the shared object or call a passed in delegate.
Here’s an example implementation using a shared object to imitate ref and out for use with async methods and other various scenarios where ref and out aren’t available:
class Ref<T>
{
// Field rather than a property to support passing to functions
// accepting `ref T` or `out T`.
public T Value;
}
async Task OperationExampleAsync(Ref<int> successfulLoopsRef)
{
var things = new[] { 0, 1, 2, };
var i = 0;
while (true)
{
// Fourth iteration will throw an exception, but we will still have
// communicated data back to the caller via successfulLoopsRef.
things[i] += i;
successfulLoopsRef.Value++;
i++;
}
}
async Task UsageExample()
{
var successCounterRef = new Ref<int>();
// Note that it does not make sense to access successCounterRef
// until OperationExampleAsync completes (either fails or succeeds)
// because there’s no synchronization. Here, I think of passing
// the variable as “temporarily giving ownership” of the referenced
// object to OperationExampleAsync. Deciding on conventions is up to
// you and belongs in documentation ^^.
try
{
await OperationExampleAsync(successCounterRef);
}
finally
{
Console.WriteLine($"Had {successCounterRef.Value} successful loops.");
}
}
Here's the code of #dcastro's answer modified for C# 7.0 with named tuples and tuple deconstruction, which streamlines the notation:
public async void Method1()
{
// Version 1, named tuples:
// just to show how it works
/*
var tuple = await GetDataTaskAsync();
int op = tuple.paramOp;
int result = tuple.paramResult;
*/
// Version 2, tuple deconstruction:
// much shorter, most elegant
(int op, int result) = await GetDataTaskAsync();
}
public async Task<(int paramOp, int paramResult)> GetDataTaskAsync()
{
//...
return (1, 2);
}
For details about the new named tuples, tuple literals and tuple deconstructions see:
https://blogs.msdn.microsoft.com/dotnet/2017/03/09/new-features-in-c-7-0/
The limitation of the async methods not accepting out parameters applies only to the compiler-generated async methods, these declared with the async keyword. It doesn't apply to hand-crafted async methods. In other words it is possible to create Task returning methods accepting out parameters. For example lets say that we already have a ParseIntAsync method that throws, and we want to create a TryParseIntAsync that doesn't throw. We could implement it like this:
public static Task<bool> TryParseIntAsync(string s, out Task<int> result)
{
var tcs = new TaskCompletionSource<int>();
result = tcs.Task;
return ParseIntAsync(s).ContinueWith(t =>
{
if (t.IsFaulted)
{
tcs.SetException(t.Exception.InnerException);
return false;
}
tcs.SetResult(t.Result);
return true;
}, default, TaskContinuationOptions.None, TaskScheduler.Default);
}
Using the TaskCompletionSource and the ContinueWith method is a bit awkward, but there is no other option since we can't use the convenient await keyword inside this method.
Usage example:
if (await TryParseIntAsync("-13", out var result))
{
Console.WriteLine($"Result: {await result}");
}
else
{
Console.WriteLine($"Parse failed");
}
Update: If the async logic is too complex to be expressed without await, then it could be encapsulated inside a nested asynchronous anonymous delegate. A TaskCompletionSource would still be needed for the out parameter. It is possible that the out parameter could be completed before
the completion of the main task, as in the example bellow:
public static Task<string> GetDataAsync(string url, out Task<int> rawDataLength)
{
var tcs = new TaskCompletionSource<int>();
rawDataLength = tcs.Task;
return ((Func<Task<string>>)(async () =>
{
var response = await GetResponseAsync(url);
var rawData = await GetRawDataAsync(response);
tcs.SetResult(rawData.Length);
return await FilterDataAsync(rawData);
}))();
}
This example assumes the existence of three asynchronous methods GetResponseAsync, GetRawDataAsync and FilterDataAsync that are called
in succession. The out parameter is completed on the completion of the second method. The GetDataAsync method could be used like this:
var data = await GetDataAsync("http://example.com", out var rawDataLength);
Console.WriteLine($"Data: {data}");
Console.WriteLine($"RawDataLength: {await rawDataLength}");
Awaiting the data before awaiting the rawDataLength is important in this simplified example, because in case of an exception the out parameter will never be completed.
I think using ValueTuples like this can work. You have to add the ValueTuple NuGet package first though:
public async void Method1()
{
(int op, int result) tuple = await GetDataTaskAsync();
int op = tuple.op;
int result = tuple.result;
}
public async Task<(int op, int result)> GetDataTaskAsync()
{
int x = 5;
int y = 10;
return (op: x, result: y):
}
Pattern matching to the rescue! C#9 (I think) onwards:
// example of a method that would traditionally would use an out parameter
public async Task<(bool success, int? value)> TryGetAsync()
{
int? value = // get it from somewhere
return (value.HasValue, value);
}
Use it like this:
if (await TryGetAsync() is (true, int value))
{
Console.WriteLine($"This is the value: {value}");
}
This is very similar to the answer provided by Michael Gehling, but I had my own solution until I found his and noticed that I wasn't the first to think of using an implicit conversion.
Regardless, I wanted to share as mine also supports when nullable is set to enable
public readonly struct TryResult<TOut>
{
#region constructors
public TryResult(bool success, TOut? value) => (Success, Value) = (success, value);
#endregion
#region properties
public bool Success { get; init; }
[MemberNotNullWhen(true, nameof(Success))] public TOut? Value { get; init; }
#endregion
#region methods
public static implicit operator bool(TryResult<TOut> result) => result.Success;
public static implicit operator TryResult<TOut>(TOut value) => new (true, value);
public void Deconstruct(out bool success, out TOut? value) => (success, value) = (Success, Value);
public TryResult<TOut> Out([NotNullWhen(true)] out TOut? value)
{
value = Value;
return this;
}
#endregion
}
Then you can write a Try method like this:
public static async Task<TryResult<byte[]>> TryGetBytesAsync(string file) =>
File.Exists(file)
? await File.ReadAllBytesAsync(file)
: default(TryResult<byte[]>);
And call it like this:
if ((await TryGetBytesAsync(file)).Out(out var bytes))
Console.WriteLine($"File has {bytes.Length} bytes.");
For developers who REALLY want to keep it in parameter, here might be another workaround.
Change the parameter to an array or List to wrap the actual value up. Remember to initialize the list before sending into the method. After returned, be sure to check value existence before consuming it. Code with caution.
You can do this by using TPL (task parallel library) instead of direct using await keyword.
private bool CheckInCategory(int? id, out Category category)
{
if (id == null || id == 0)
category = null;
else
category = Task.Run(async () => await _context.Categories.FindAsync(id ?? 0)).Result;
return category != null;
}
if(!CheckInCategory(int? id, out var category)) return error
I have an async delegate which I await in the async method:
async Task M1()
{
Debug.WriteLine("M1.A");
await Task.Delay(10);
Debug.WriteLine("M1.B");
}
async Task M2()
{
Debug.WriteLine("M2.A");
await Task.Delay(1);
Debug.WriteLine("M2.B");
}
delegate Task MyDel();
async void button_Click(object sender, RoutedEventArgs e)
{
MyDel del = null;
del += M1;
del += M2;
await del();
}
The output is:
M1.A
M2.A
M2.B
M1.B
That is, both invocation members go off simultaneously, not awaiting each other. I need them await each other so the output would be:
M1.A
M1.B
M2.A
M2.B
I tried this in place of await del():
foreach (MyDel member in del.GetInvocationList())
{
await member();
}
This works. However, I have lots of code places where this needs to be done. Delegates can have different number of parameters of various types but they all return Task.
How can I write an extension method which will let me run the code above by making calls like this?
del0.AwaitOneByOne(); // del0 is 'delegate Task Method()'
del1.AwaitOneByOne(paramInt1, paramStr2); // del1 is 'delegate Task Method(int, string)'
del2.AwaitOneByOne(paramBytes1); // del2 is 'delegate Task Method(byte[])'
If you use Func for you delegates rather than custom delegates you could write something like this:
public static class FuncHelper
{
public static async Task RunSequential<T1>(this Func<T1,Task> del, T1 param1)
{
foreach (var d in del.GetInvocationList().OfType<Func<T1, Task>>())
{
await d(param1);
}
}
public static async Task RunSequential<T1, T2>(this Func<T1, T2, Task> del, T1 param1, T2 param2)
{
foreach (var d in del.GetInvocationList().OfType<Func<T1, T2, Task>>())
{
await d(param1, param2);
}
}
// Additional methods for more parameters go here
}
It does seem that you are trying to use delegates in ways they were not really intended. They aren't really supposed to control order or have the functions rely on each other to complete.
Probably better off making a custom collection, maybe override += and -= if you want some delegate like behavior.
The cause of your problem is that your delegates have a different set of parameters.
The solution is to create an extra delegate that contains the call inclusive the parameters, similar to the System.Windows.Forms.MethodInvoker delegate.
The only difference in your methodInvoker is that your methodInvoker is not a delegate that returns void, but a delegate that returns a Task.
The function in your extension class would be similar to your foreach:
public delegate task MethodInvoker();
static class DelegateExtensions
{
public static async Task ExecuteDelegates(this IEnumerable<MethodInvoker> methodInvokers)
{
foreach (var methodInvoker in methodInvokers)
{
await methodInvoker();
}
}
}
Usage would be like:
public MyClass
{
private async Task F1()
{
Debug.WriteLine("Begin F1");
await Task.Delay(TimeSpan.FromSeconds(1));
Debug.WriteLine("F1 Completed");
}
private async Task F2(TimeSpan waitTime)
{
Debug.WriteLine("Begin F2");
await Task.Delay(waitTime);
Debug.WriteLine("F2 Completed");
}
private async Task F3(int count, TimeSpan waitTime)
{
Debug.WriteLine("Begin F3");
for (int i = 0; i < count; ++i)
{
await Task.Delay(waitTime);
}
Debug.WriteLine("F3 Completed");
}
}
public async Task ExecuteMyFunctions()
{
MyClass X = new MyClass();
IEnumerable<MethodInvoker> myMethodInvokers = new MethodInvoker[]
{
() => X.F1(),
() => X.F2(TimeSpan.FromSeconds(1)),
() => X.F3(4, TimeSpan.FromSeconds(0.25)),
}
await myMethodInvokers.ExecuteDelegates();
}
When trying to answer the following question, I wrote this piece of code :
using static MyNameSpace.Locker; //So that we don't need to specify the static class name before each call.
public class MainClass
{
public MainMethod()
{
Lock(new object()).Lock(new object()).RunAction(() => Console.WriteLine("Finished"));
}
}
public static class Locker
{
public static async Task<List<object>> Lock(object toLock, int timeout = -1)
{
await Task.Run(() => TryEnter(toLock, timeout));
return new List<object>() { toLock };
}
public static async Task<List<object>> Lock(
this Task<List<object>> lockedChain,
object toLock,
int timeout = -1)
{
await Task.Run(() => TryEnter(toLock, timeout));
await lockedChain;
lockedChain.Result.Add(toLock)
return lockedChain.Result;
}
public static async void RunAction(this Task<List<object>> lockChain, Action toRun)
{
await lockChain;
try
{
toRun.Invoke();
}
finally
{
foreach (var chainMember in lockChain.Result)
{
Monitor.Exit(chainMember);
}
}
}
private static void TryEnter(object toLock, int timeout = -1)
{
var success = false;
if (timeout > 0)
{
success = Monitor.TryEnter(toLock, timeout);
}
else
{
success = Monitor.TryEnter(toLock);
}
if (!success)
{
throw new TimeoutException();
}
}
}
But as some user rightfully remarked, this won't work for a very simple reason : Since the methods are async, they may not run on the same thread, thus throwing an exception when trying to release the Monitor.
How would one go to ensure the Enter and Exit method of the monitor a run on the same thread ?
Instead of forcing the lock operations onto the same thread which is nearly impossible, use a lock that is not thread-affine: SemaphoreSlim. It has native async support as well (as opposed to blocking).
In the original question that you linked to I'd go with this answer instead. Seems cleaner than the chain solution which contains a lot of artificial complexity. Code quality is not so much about the specific call syntax being used. Just by putting things in a syntactic chain you cannot reduce complexity much.
In particular the chain solution is just a complicated way of saying Lock(new [] { lock1, lock2 }, () => ...); I think. All the chain does it build up a list. using makes this even simpler because it does away with the lambda. Lambdas are less composable because you can't return from the lambda like you can from using. I think you should target this:
using (MultiLock(new [] { lock1, lock2 }, timeout)) {
//...
}
I want to write an async method with an out parameter, like this:
public async void Method1()
{
int op;
int result = await GetDataTaskAsync(out op);
}
How do I do this in GetDataTaskAsync?
You can't have async methods with ref or out parameters.
Lucian Wischik explains why this is not possible on this MSDN thread: http://social.msdn.microsoft.com/Forums/en-US/d2f48a52-e35a-4948-844d-828a1a6deb74/why-async-methods-cannot-have-ref-or-out-parameters
As for why async methods don't support out-by-reference parameters?
(or ref parameters?) That's a limitation of the CLR. We chose to
implement async methods in a similar way to iterator methods -- i.e.
through the compiler transforming the method into a
state-machine-object. The CLR has no safe way to store the address of
an "out parameter" or "reference parameter" as a field of an object.
The only way to have supported out-by-reference parameters would be if
the async feature were done by a low-level CLR rewrite instead of a
compiler-rewrite. We examined that approach, and it had a lot going
for it, but it would ultimately have been so costly that it'd never
have happened.
A typical workaround for this situation is to have the async method return a Tuple instead.
You could re-write your method as such:
public async Task Method1()
{
var tuple = await GetDataTaskAsync();
int op = tuple.Item1;
int result = tuple.Item2;
}
public async Task<Tuple<int, int>> GetDataTaskAsync()
{
//...
return new Tuple<int, int>(1, 2);
}
The C#7+ Solution is to use implicit tuple syntax.
private async Task<(bool IsSuccess, IActionResult Result)> TryLogin(OpenIdConnectRequest request)
{
return (true, BadRequest(new OpenIdErrorResponse
{
Error = OpenIdConnectConstants.Errors.AccessDenied,
ErrorDescription = "Access token provided is not valid."
}));
}
return result utilizes the method signature defined property names. e.g:
var foo = await TryLogin(request);
if (foo.IsSuccess)
return foo.Result;
You cannot have ref or out parameters in async methods (as was already noted).
This screams for some modelling in the data moving around:
public class Data
{
public int Op {get; set;}
public int Result {get; set;}
}
public async void Method1()
{
Data data = await GetDataTaskAsync();
// use data.Op and data.Result from here on
}
public async Task<Data> GetDataTaskAsync()
{
var returnValue = new Data();
// Fill up returnValue
return returnValue;
}
You gain the ability to reuse your code more easily, plus it's way more readable than variables or tuples.
I had the same problem as I like using the Try-method-pattern which basically seems to be incompatible to the async-await-paradigm...
Important to me is that I can call the Try-method within a single if-clause and do not have to pre-define the out-variables before, but can do it in-line like in the following example:
if (TryReceive(out string msg))
{
// use msg
}
So I came up with the following solutions:
Note: The new solution is superior, because it can be used with methods that simply return a tuple as described in many of the other answers here, what might often be found in existing code!
New solution:
Create extension methods for ValueTuples:
public static class TupleExtensions
{
public static bool TryOut<P2>(this ValueTuple<bool, P2> tuple, out P2 p2)
{
bool p1;
(p1, p2) = tuple;
return p1;
}
public static bool TryOut<P2, P3>(this ValueTuple<bool, P2, P3> tuple, out P2 p2, out P3 p3)
{
bool p1;
(p1, p2, p3) = tuple;
return p1;
}
// continue to support larger tuples...
}
Define async Try-method like this:
public async Task<(bool, string)> TryReceiveAsync()
{
string message;
bool success;
// ...
return (success, message);
}
Call the async Try-method like this:
if ((await TryReceiveAsync()).TryOut(out string msg))
{
// use msg
}
Old solution:
Define a helper struct:
public struct AsyncOut<T, OUT>
{
private readonly T returnValue;
private readonly OUT result;
public AsyncOut(T returnValue, OUT result)
{
this.returnValue = returnValue;
this.result = result;
}
public T Out(out OUT result)
{
result = this.result;
return returnValue;
}
public T ReturnValue => returnValue;
public static implicit operator AsyncOut<T, OUT>((T returnValue ,OUT result) tuple) =>
new AsyncOut<T, OUT>(tuple.returnValue, tuple.result);
}
Define async Try-method like this:
public async Task<AsyncOut<bool, string>> TryReceiveAsync()
{
string message;
bool success;
// ...
return (success, message);
}
Call the async Try-method like this:
if ((await TryReceiveAsync()).Out(out string msg))
{
// use msg
}
For multiple out parameters you can define additional structs (e.g. AsyncOut<T,OUT1, OUT2>) or you can return a tuple.
Alex made a great point on readability. Equivalently, a function is also interface enough to define the type(s) being returned and you also get meaningful variable names.
delegate void OpDelegate(int op);
Task<bool> GetDataTaskAsync(OpDelegate callback)
{
bool canGetData = true;
if (canGetData) callback(5);
return Task.FromResult(canGetData);
}
Callers provide a lambda (or a named function) and intellisense helps by copying the variable name(s) from the delegate.
int myOp;
bool result = await GetDataTaskAsync(op => myOp = op);
This particular approach is like a "Try" method where myOp is set if the method result is true. Otherwise, you don't care about myOp.
I love the Try pattern. It's a tidy pattern.
if (double.TryParse(name, out var result))
{
// handle success
}
else
{
// handle error
}
But, it's challenging with async. That doesn't mean we don't have real options. Here are the three core approaches you can consider for async methods in a quasi-version of the Try pattern.
Approach 1 - output a structure
This looks most like a sync Try method only returning a tuple instead of a bool with an out parameter, which we all know is not permitted in C#.
var result = await DoAsync(name);
if (result.Success)
{
// handle success
}
else
{
// handle error
}
With a method that returns true of false and never throws an exception.
Remember, throwing an exception in a Try method breaks the whole purpose of the pattern.
async Task<(bool Success, StorageFile File, Exception exception)> DoAsync(string fileName)
{
try
{
var folder = ApplicationData.Current.LocalCacheFolder;
return (true, await folder.GetFileAsync(fileName), null);
}
catch (Exception exception)
{
return (false, null, exception);
}
}
Approach 2 - pass in callback methods
We can use anonymous methods to set external variables. It's clever syntax, though slightly complicated. In small doses, it's fine.
var file = default(StorageFile);
var exception = default(Exception);
if (await DoAsync(name, x => file = x, x => exception = x))
{
// handle success
}
else
{
// handle failure
}
The method obeys the basics of the Try pattern but sets out parameters to passed in callback methods. It's done like this.
async Task<bool> DoAsync(string fileName, Action<StorageFile> file, Action<Exception> error)
{
try
{
var folder = ApplicationData.Current.LocalCacheFolder;
file?.Invoke(await folder.GetFileAsync(fileName));
return true;
}
catch (Exception exception)
{
error?.Invoke(exception);
return false;
}
}
There's a question in my mind about performance here. But, the C# compiler is so freaking smart, that I think you're safe choosing this option, almost for sure.
Approach 3 - use ContinueWith
What if you just use the TPL as designed? No tuples. The idea here is that we use exceptions to redirect ContinueWith to two different paths.
await DoAsync(name).ContinueWith(task =>
{
if (task.Exception != null)
{
// handle fail
}
if (task.Result is StorageFile sf)
{
// handle success
}
});
With a method that throws an exception when there is any kind of failure. That's different than returning a boolean. It's a way to communicate with the TPL.
async Task<StorageFile> DoAsync(string fileName)
{
var folder = ApplicationData.Current.LocalCacheFolder;
return await folder.GetFileAsync(fileName);
}
In the code above, if the file is not found, an exception is thrown. This will invoke the failure ContinueWith that will handle Task.Exception in its logic block. Neat, huh?
Listen, there's a reason we love the Try pattern. It's fundamentally so neat and readable and, as a result, maintainable. As you choose your approach, watchdog for readability. Remember the next developer who in 6 months and doesn't have you to answer clarifying questions. Your code can be the only documentation a developer will ever have.
Best of luck.
One nice feature of out parameters is that they can be used to return data even when a function throws an exception. I think the closest equivalent to doing this with an async method would be using a new object to hold the data that both the async method and caller can refer to. Another way would be to pass a delegate as suggested in another answer.
Note that neither of these techniques will have any of the sort of enforcement from the compiler that out has. I.e., the compiler won’t require you to set the value on the shared object or call a passed in delegate.
Here’s an example implementation using a shared object to imitate ref and out for use with async methods and other various scenarios where ref and out aren’t available:
class Ref<T>
{
// Field rather than a property to support passing to functions
// accepting `ref T` or `out T`.
public T Value;
}
async Task OperationExampleAsync(Ref<int> successfulLoopsRef)
{
var things = new[] { 0, 1, 2, };
var i = 0;
while (true)
{
// Fourth iteration will throw an exception, but we will still have
// communicated data back to the caller via successfulLoopsRef.
things[i] += i;
successfulLoopsRef.Value++;
i++;
}
}
async Task UsageExample()
{
var successCounterRef = new Ref<int>();
// Note that it does not make sense to access successCounterRef
// until OperationExampleAsync completes (either fails or succeeds)
// because there’s no synchronization. Here, I think of passing
// the variable as “temporarily giving ownership” of the referenced
// object to OperationExampleAsync. Deciding on conventions is up to
// you and belongs in documentation ^^.
try
{
await OperationExampleAsync(successCounterRef);
}
finally
{
Console.WriteLine($"Had {successCounterRef.Value} successful loops.");
}
}
Here's the code of #dcastro's answer modified for C# 7.0 with named tuples and tuple deconstruction, which streamlines the notation:
public async void Method1()
{
// Version 1, named tuples:
// just to show how it works
/*
var tuple = await GetDataTaskAsync();
int op = tuple.paramOp;
int result = tuple.paramResult;
*/
// Version 2, tuple deconstruction:
// much shorter, most elegant
(int op, int result) = await GetDataTaskAsync();
}
public async Task<(int paramOp, int paramResult)> GetDataTaskAsync()
{
//...
return (1, 2);
}
For details about the new named tuples, tuple literals and tuple deconstructions see:
https://blogs.msdn.microsoft.com/dotnet/2017/03/09/new-features-in-c-7-0/
The limitation of the async methods not accepting out parameters applies only to the compiler-generated async methods, these declared with the async keyword. It doesn't apply to hand-crafted async methods. In other words it is possible to create Task returning methods accepting out parameters. For example lets say that we already have a ParseIntAsync method that throws, and we want to create a TryParseIntAsync that doesn't throw. We could implement it like this:
public static Task<bool> TryParseIntAsync(string s, out Task<int> result)
{
var tcs = new TaskCompletionSource<int>();
result = tcs.Task;
return ParseIntAsync(s).ContinueWith(t =>
{
if (t.IsFaulted)
{
tcs.SetException(t.Exception.InnerException);
return false;
}
tcs.SetResult(t.Result);
return true;
}, default, TaskContinuationOptions.None, TaskScheduler.Default);
}
Using the TaskCompletionSource and the ContinueWith method is a bit awkward, but there is no other option since we can't use the convenient await keyword inside this method.
Usage example:
if (await TryParseIntAsync("-13", out var result))
{
Console.WriteLine($"Result: {await result}");
}
else
{
Console.WriteLine($"Parse failed");
}
Update: If the async logic is too complex to be expressed without await, then it could be encapsulated inside a nested asynchronous anonymous delegate. A TaskCompletionSource would still be needed for the out parameter. It is possible that the out parameter could be completed before
the completion of the main task, as in the example bellow:
public static Task<string> GetDataAsync(string url, out Task<int> rawDataLength)
{
var tcs = new TaskCompletionSource<int>();
rawDataLength = tcs.Task;
return ((Func<Task<string>>)(async () =>
{
var response = await GetResponseAsync(url);
var rawData = await GetRawDataAsync(response);
tcs.SetResult(rawData.Length);
return await FilterDataAsync(rawData);
}))();
}
This example assumes the existence of three asynchronous methods GetResponseAsync, GetRawDataAsync and FilterDataAsync that are called
in succession. The out parameter is completed on the completion of the second method. The GetDataAsync method could be used like this:
var data = await GetDataAsync("http://example.com", out var rawDataLength);
Console.WriteLine($"Data: {data}");
Console.WriteLine($"RawDataLength: {await rawDataLength}");
Awaiting the data before awaiting the rawDataLength is important in this simplified example, because in case of an exception the out parameter will never be completed.
I think using ValueTuples like this can work. You have to add the ValueTuple NuGet package first though:
public async void Method1()
{
(int op, int result) tuple = await GetDataTaskAsync();
int op = tuple.op;
int result = tuple.result;
}
public async Task<(int op, int result)> GetDataTaskAsync()
{
int x = 5;
int y = 10;
return (op: x, result: y):
}
Pattern matching to the rescue! C#9 (I think) onwards:
// example of a method that would traditionally would use an out parameter
public async Task<(bool success, int? value)> TryGetAsync()
{
int? value = // get it from somewhere
return (value.HasValue, value);
}
Use it like this:
if (await TryGetAsync() is (true, int value))
{
Console.WriteLine($"This is the value: {value}");
}
This is very similar to the answer provided by Michael Gehling, but I had my own solution until I found his and noticed that I wasn't the first to think of using an implicit conversion.
Regardless, I wanted to share as mine also supports when nullable is set to enable
public readonly struct TryResult<TOut>
{
#region constructors
public TryResult(bool success, TOut? value) => (Success, Value) = (success, value);
#endregion
#region properties
public bool Success { get; init; }
[MemberNotNullWhen(true, nameof(Success))] public TOut? Value { get; init; }
#endregion
#region methods
public static implicit operator bool(TryResult<TOut> result) => result.Success;
public static implicit operator TryResult<TOut>(TOut value) => new (true, value);
public void Deconstruct(out bool success, out TOut? value) => (success, value) = (Success, Value);
public TryResult<TOut> Out([NotNullWhen(true)] out TOut? value)
{
value = Value;
return this;
}
#endregion
}
Then you can write a Try method like this:
public static async Task<TryResult<byte[]>> TryGetBytesAsync(string file) =>
File.Exists(file)
? await File.ReadAllBytesAsync(file)
: default(TryResult<byte[]>);
And call it like this:
if ((await TryGetBytesAsync(file)).Out(out var bytes))
Console.WriteLine($"File has {bytes.Length} bytes.");
For developers who REALLY want to keep it in parameter, here might be another workaround.
Change the parameter to an array or List to wrap the actual value up. Remember to initialize the list before sending into the method. After returned, be sure to check value existence before consuming it. Code with caution.
You can do this by using TPL (task parallel library) instead of direct using await keyword.
private bool CheckInCategory(int? id, out Category category)
{
if (id == null || id == 0)
category = null;
else
category = Task.Run(async () => await _context.Categories.FindAsync(id ?? 0)).Result;
return category != null;
}
if(!CheckInCategory(int? id, out var category)) return error
I know how to make Async methods but say I have a method that does a lot of work then returns a boolean value?
How do I return the boolean value on the callback?
Clarification:
public bool Foo(){
Thread.Sleep(100000); // Do work
return true;
}
I want to be able to make this asynchronous.
From C# 5.0, you can specify the method as
public async Task<bool> doAsyncOperation()
{
// do work
return true;
}
bool result = await doAsyncOperation();
There are a few ways of doing that... the simplest is to have the async method also do the follow-on operation. Another popular approach is to pass in a callback, i.e.
void RunFooAsync(..., Action<bool> callback) {
// do some stuff
bool result = ...
if(callback != null) callback(result);
}
Another approach would be to raise an event (with the result in the event-args data) when the async operation is complete.
Also, if you are using the TPL, you can use ContinueWith:
Task<bool> outerTask = ...;
outerTask.ContinueWith(task =>
{
bool result = task.Result;
// do something with that
});
Use a BackgroundWorker. It will allow you to get callbacks on completion and allow you to track progress. You can set the Result value on the event arguments to the resulting value.
public void UseBackgroundWorker()
{
var worker = new BackgroundWorker();
worker.DoWork += DoWork;
worker.RunWorkerCompleted += WorkDone;
worker.RunWorkerAsync("input");
}
public void DoWork(object sender, DoWorkEventArgs e)
{
e.Result = e.Argument.Equals("input");
Thread.Sleep(1000);
}
public void WorkDone(object sender, RunWorkerCompletedEventArgs e)
{
var result = (bool) e.Result;
}
Probably the simplest way to do it is to create a delegate and then BeginInvoke, followed by a wait at some time in the future, and an EndInvoke.
public bool Foo(){
Thread.Sleep(100000); // Do work
return true;
}
public SomeMethod()
{
var fooCaller = new Func<bool>(Foo);
// Call the method asynchronously
var asyncResult = fooCaller.BeginInvoke(null, null);
// Potentially do other work while the asynchronous method is executing.
// Finally, wait for result
asyncResult.AsyncWaitHandle.WaitOne();
bool fooResult = fooCaller.EndInvoke(asyncResult);
Console.WriteLine("Foo returned {0}", fooResult);
}
Perhaps you can try to BeginInvoke a delegate pointing to your method like so:
delegate string SynchOperation(string value);
class Program
{
static void Main(string[] args)
{
BeginTheSynchronousOperation(CallbackOperation, "my value");
Console.ReadLine();
}
static void BeginTheSynchronousOperation(AsyncCallback callback, string value)
{
SynchOperation op = new SynchOperation(SynchronousOperation);
op.BeginInvoke(value, callback, op);
}
static string SynchronousOperation(string value)
{
Thread.Sleep(10000);
return value;
}
static void CallbackOperation(IAsyncResult result)
{
// get your delegate
var ar = result.AsyncState as SynchOperation;
// end invoke and get value
var returned = ar.EndInvoke(result);
Console.WriteLine(returned);
}
}
Then use the value in the method you sent as AsyncCallback to continue..
You should use the EndXXX of your async method to return the value. EndXXX should wait until there is a result using the IAsyncResult's WaitHandle and than return with the value.