c# Generic function as a parameter - c#

I have this function:
private async Task Wizardry<T>(Func<T theParameter, Task> method)
{
try
{
await method(theParameter);
}
catch
{ }
}
and the way I see it working is like this:
await this.Wizardry<Email>(this.emailProvider.SendAsync(email));
await this.Wizardry<Log>(this.SaveLog(log));
but obviously that does not work.
Does anyone know how I can achieve this?

Is this what you need:
private async Task Wizardry<T>(Func<T, Task> method, T theParameter)
{
try
{
await method(theParameter);
}
catch
{
}
}
And invoke it like:
await this.Wizardry<string>((z)=> Task.Run(()=>Console.WriteLine(z)), "test");

You are attempting to create a Func where you want to pass in parameters while you haven't got any parameters to pass in.
A non-generic Func<Task> will do:
await this.Wizardry(() => this.emailProvider.SendAsync(email));
await this.Wizardry(() => this.SaveLog(log));
private async Task Wizardry(Func<Task> method)
{
await method();
}

I can see 2 possibilities:
private async Task Wizardry(Func<Task> method) {
try {
await method();
} catch {
}
}
Which is called with:
this.Wizardry(() => this.emailProvider.SendAsync(email));
Or
private async Task Wizardry<T>(Func<T, Task> method, T theParameter) {
try {
await method(theParameter);
} catch {
}
}
Which is called with:
this.Wizardry(this.emailProvider.SendAsync, email);

Related

Race condition with async/await, how to resolve

I have a problem with async/await in C#, i need it to get some object called Trades, after i get it, it needs to SAVE it. Problem is, with async/await, it is doing the SAVE first, and then go and get my trade objects. How do i ensure i get the objects first, and then does the saving.... here is my code...
private async void OnRefresh()
{
try
{
var trades = await ExchangeServiceInstance.GetTrades("");
mmTrades = new ObservableCollection<EEtrade>(trades);
tradeListView.ItemsSource = mmTrades;
}
catch { }
}
public async void OnSignalReceived()
{
// THIS NEEDS TO FINISH FIRST, BUT IT DOESN'T
await tradeListView.Dispatcher.InvokeAsync((Action)async delegate
{
if (ExchangeServiceInstance.SelectedTabIndex == CURRENT_TAB_INDEX_ITEM)
{
await Task.Delay(MMConfig.DELAYMILLISEC);
OnRefresh();
}
});
// SOMEHOW THIS GETS CALLED FIRST BEFORE THE ABOVE GETS TO FINISH!
await OnSaveTrades();
}
public async Task<int> OnSaveTrades()
{
foreach (var trade in mmTrades)
{
await ExchangeServiceInstance.OnInsertDoneTrade(trade);
}
return mmTrades.Count;
}
Any ideas guys? Thanks!
The problem is your OnRefresh method. Because the return type is void the method is not awaited [Check out this answer]. In addition you dont even try to await for the method inside your delegate
Changing the method to the following:
private async Task OnRefresh()
{
try
{
var trades = await ExchangeServiceInstance.GetTrades("");
mmTrades = new ObservableCollection<EEtrade>(trades);
tradeListView.ItemsSource = mmTrades;
}
catch { }
}
And await this method inside your delegate, should solve your problem:
public async void OnSignalReceived()
{
// THIS NEEDS TO FINISH FIRST, BUT IT DOESN'T
await tradeListView.Dispatcher.InvokeAsync((Action)async delegate
{
if (ExchangeServiceInstance.SelectedTabIndex == CURRENT_TAB_INDEX_ITEM)
{
await Task.Delay(MMConfig.DELAYMILLISEC);
await OnRefresh();
}
});
// SOMEHOW THIS GETS CALLED FIRST BEFORE THE ABOVE GETS TO FINISH!
await OnSaveTrades();
}
The use of (Action)async is basically the same as async void, and async void is almost always a mistake. Specifically, the consumer cannot know the outcome (unless it faults synchronously). The dispatcher here isn't really thinking of async.
If we assume that you must use the dispatcher here, perhaps a workaround might be to use something like a SemaphoreSlim (or maybe a TaskCompletionSource<something>) that you signal at the end of your async work (even in the exception case), and then await that; untested, but:
var tcs = new TaskCompletionSource<bool>();
await tradeListView.Dispatcher.InvokeAsync((Action)async delegate
{
try {
if (ExchangeServiceInstance.SelectedTabIndex == CURRENT_TAB_INDEX_ITEM)
{
await Task.Delay(MMConfig.DELAYMILLISEC);
OnRefresh();
}
tcs.TrySetResult(true);
} catch (Exception ex) {
tcs.TrySetException(ex);
}
});
await tcs.Task; // ensure the async work is complete
await OnSaveTrades();
First of all, you are using the async void pattern a lot. This is really bad practice for a number of reasons. You should stop doing that.
The problem here is that OnRefresh is again an async void method that can't be awaited but should be:
private async Task OnRefresh()
{
try
{
var trades = await ExchangeServiceInstance.GetTrades("");
mmTrades = new ObservableCollection<EEtrade>(trades);
tradeListView.ItemsSource = mmTrades;
}
catch { }
}
In your OnSignalReceived method change the call to OnRefresh(); to await OnRefresh();

Void task with generics in C#

I would like to reuse the following static generic Profile function in my application:
private static async Task<T> Profile<T>(Func<Task<T>> func, string operation)
{
Console.WriteLine($"{operation} is called");
return await func();
}
And I have the following interface to implement:
public interface ICustomerOperations
{
Task<Customer> GetCustomerAsync(string id);
Task DeleteCustomerAsync(string id);
}
I can use Profile method with GetCustomerAsync without any problem.
public async Task<Customer> GetCustomer(string id)
{
return await Profile(() => _customerOperations.GetCustomerAsync(id), $"GetCustomerAsync");
}
However when I try to use Profile with DeleteCustomerAsync
public async void DeleteCustomer(string id)
{
await Profile(() => _customerOperations.DeleteCustomerAsync(id), $"DeleteCustomerAsync");
}
Build failed:
The type arguments for method 'CrmService.Profile(Func<Task>,
string)' cannot be inferred from the usage. Try specifying the type
arguments explicitly.
So my question is how can I reuse Task<T> with void?
You can create an overload without duplicating the method:
private static Task Profile(Func<Task> func, string operation)
{
return Profile<object>(async () => { await func(); return null; }, operation);
}
A simple solution is to duplicate your method:
private static async Task Profile(Func<Task> func, string operation)
{
Console.WriteLine($"{operation} is called");
await func();
}
I think duplicating your method is cleaner than doing some hacks like this:
public async void DeleteCustomer(string id)
{
await Profile(async () => { await _customerOperations.DeleteCustomerAsync(id); return 0; }, $"DeleteCustomerAsync");
}

Function as parameter in async method

I call a method containing a function:
public void DoMagicStuff(Func<T> anyfunction) {
// do lots of magic stuff
}
This works:
public void DoNonAsyncStuff() {
DoMagicStuff(()=> {
AnotherFunction();
}
}
While this does not:
public async Task<CustomClass> DoAsynStuff() {
DoMagicStuff(()=> {
return await DoSomethingDifferent();
}
}
"The await operator can only be used in async functions"
How do I make this work for async methods?
If you intend to pass asynchronous delegates to DoMagicStuff, then you need to overload that with an asynchronous version:
public void DoMagicStuff(Func<T> anyfunction)
{
// do lots of magic stuff
T t = anyfunction();
}
public async Task DoMagicStuff(Func<Task> asyncfunction)
{
// do lots of magic stuff
T t = await asyncfunction();
}
This allows you to call await for the asyncfunction.
Any common logic can always be refactored into another method.
With regard to your question, await can only be used in a function that has been declared async, which your lambda hasn't.
It should be like this:
public async Task<CustomClass> DoAsynStuff()
{
await DoMagicStuff(async () =>
{
return await DoSomethingDifferent();
});
}
And in fact, because DoSomethingDifferent already returns a Task, the lambda is superfluous:
public async Task<CustomClass> DoAsynStuff()
{
await DoMagicStuff(DoSomethingDifferent);
}

Encapsulate async method in Func<T>

First, i hope the title is okay.
I have a Grpc Client with the well known greeter service and try to encapsulate the SayHelloAsync call in a Func.
But the => operator is redlined because he can not convert the expression he say.
It works if i remove any async/await.
Its probably because SayHelloAsync returns AsyncUnaryCall(which have an awaiter) instead of Task but at the end its
not a Grpc issue i guess, its just my missunderstanding.
Here is my try:
static async Task Main()
{
var client = CreateGreeterClient();
await UnsafeTask<Service.HelloReply>(async () =>
{
var result = await client.SayHelloAsync(new Service.HelloRequest { Name = greeter.Name });
return Task<Service.HelloReply>.FromResult(result);
});
Console.ReadKey();
}
static async Task<T> UnsafeTask<T>(Func<AsyncUnaryCall<T>> method) where T:class
{
try
{
return await method();
}
catch (Exception exception)
{
Console.WriteLine(exception.Message);
return null;
}
}
Any tip would be greatful.

await a Task and silently stop on cancel or failure

What I would like to write is the following:
async void Foo()
{
var result = await GetMyTask().IgnoreCancelAndFailure();
ProcessResult(result);
}
Instead of:
void Foo()
{
GetMyTask().ContinueWith(task => ProcessResult(task.Result),
TaskContinuationOptions.OnlyOnRanToCompletion);
}
However I don't know how to implement the method IgnoreCancelAndFailure, which would have the following signature:
//On cancel or failure this task should simply stop and never complete.
Task<T> IgnoreCancelAndFailure<T>(this Task<T> task)
{
throw new NotImplementedException();
}
If possible, how should I implement IgnoreCancelAndFailure?
You could do something like that, but you need to know what you want the method to return in case of failure, since a return value is expected:
public static async Task<T> IgnoreCancelAndFailure<T>(this Task<T> task)
{
try
{
return await task;
}
catch
{
return ???; // whatever you want to return in this case
}
}
If it's a Task with no result, just leave the catch empty (or perhaps log the exception... swallowed exceptions make for hard debugging)
If you just want to execute ProcessResult only when GetMyTask succeeds, you can do this:
async void Foo()
{
try
{
var result = await GetMyTask();
ProcessResult(result);
}
catch(Exception ex)
{
// handle the exception somehow, or ignore it (not recommended)
}
}
You will never be able to stop your code from continuing expect when killing the thread or process. keep in mind that the await task can be considered a function call that will always have to return a value or throw an exception.
The closest way to shorten your code is creating a wrapper function that uses the ProcessResult method as Action argument.
Something like that:
public static async Task IgnoreCancelAndFailure<T>(this Task<T> task, Action<T> resultProcessor)
{
task.ContinueWith(t => resultProcessor(t.Result),
TaskContinuationOptions.OnlyOnRanToCompletion);
}
async void Foo()
{
GetMyTask().IgnoreCancelAndFailure(ProcessResult);
}
I think I found the answer. The following seems to do the trick. It uses the awaitable pattern. Could you guys confirm that this isn't evil?
class User
{
async void Foo()
{
var result = await GetMyTask().IgnoreCancelAndFailure();
ProcessResult(result);
}
}
public static class TaskExtenstions
{
public static SilentTask<T> IgnoreCancelAndFailure<T>(this Task<T> task)
{
return new SilentTask<T>(task);
}
}
public class SilentTask<T>
{
private readonly Task<T> _inner;
public SilentTask(Task<T> inner)
{
_inner = inner;
}
public SilentAwaiter GetAwaiter()
{
return new SilentAwaiter(_inner);
}
public class SilentAwaiter : INotifyCompletion
{
private readonly TaskAwaiter<T> _inner;
private readonly Task<T> _task;
public SilentAwaiter(Task<T> task)
{
_task = task;
_inner = task.GetAwaiter();
}
public bool IsCompleted
{
get
{
return _task.Status == TaskStatus.RanToCompletion;
}
}
public void OnCompleted(Action continuation)
{
_inner.OnCompleted(() =>
{
if (IsCompleted)
{
continuation();
}
});
}
public T GetResult()
{
return _inner.GetResult();
}
}
}

Categories