How to use action delegate to avoid if else - c#

I have the following code:
public class NotificationService {
private readonly Dictionary<NotificationMessageType, Action<IList<RecipientDetail>, NotificationMessageType>> _actionMap;
public NotificationService() [
_actionMap = new Dictionary<NotificationMessageType, Action<IList<RecipientDetail>, NotificationMessageType>> ();
_actionMap.Add(NotificationMessageType.SessionBookedReminder, new Action<IList<RecipientDetail>, NotificationMessageType>(GenerateNotificationsAsync)); //getting errror here because of async await
}
public async Task GenerateNotificationsAsync(IList<RecipientDetail> usersToNotify, NotificationMessageType messageType)
{
Would like to avoid if else here:
if(messageType == NotificationMessageType.SessionBookedReminder)
{
await Task.WhenAll(usersToNotify.Select(u => GenerateBookingNotificationAsync(u, messageType)).ToArray());
}
else
{
await Task.WhenAll(usersToNotify.Select(u => SendNotificationAsync(u, messageType)).ToArray());
}
}
public async Task GenerateNotificationsAsync(IList<RecipientDetail> usersToNotify, NotificationMessageType messageType)
{
}
public async Task GenerateBookingNotificationAsync(RecipientDetail userToNotify, NotificationMessageType messageType)
{
}
}
How can I use action delegate to avoid if else. I've tried with following, but getting error due to async await.
Can anyone help how to do the right way?
Thanks

Your dictionary must match the method declaration, your methods returns a task, so your
Action<IList<RecipientDetail>, NotificationMessageType>
Must be changed to something like
Func<IList<RecipientDetail>, NotificationMessageType,Task>
your method must return a task in order to use it in a async/await manner

Related

Get method name and parameters when it's invoked through a task queue

I have a simple task queue that allows one task to execute at a time:
public class TaskQueue
{
public SemaphoreSlim semaphore;
public TaskQueue()
{
semaphore = new SemaphoreSlim(1);
}
public async Task<T> Enqueue<T>(Func<Task<T>> taskGenerator)
{
await semaphore.WaitAsync();
try
{
return await taskGenerator();
}
finally
{
semaphore.Release();
}
}
public async Task Enqueue(Func<Task> taskGenerator)
{
await semaphore.WaitAsync();
try
{
await taskGenerator();
}
finally
{
semaphore.Release();
}
}
}
And I would queue a task in there like so:
private async Task SaveData()
{
//some code
await taskQueue.Enqueue(async () => { printed = await pm.Print(Template); });
//some code
}
Now what I would like to do is inside the Enqueue method add a log that will contain the info $Print was called with parameter {Template}. How can I get the name of the method executed and it's parameters?
I know I can do [CallerMemberName] string caller = "" to get info that the call was made inside SaveData, but is there an attribute or something to log the info I want?
this is possible (expression trees, etc), but it is incredibly inefficient; perhaps a better approach is to enqueue an object instead, i.e.
abstract class ThingToDo {
public abstract Task DoTheThingAsync();
}
and make your queue a queue of ThingToDo instead of Func<Task<T>>, then you can have things like:
sealed class PrintThing : ThingToDo {
private readonly int x;
private readonly string y;
private readonly string caller;
public PrintThing(int x, string y, [CallerMemberName] string caller = null) {
this.x = x;
this.y = y;
this.caller = caller;
}
public override Task DoTheThingAsync() {...}
public override ToString() => $"{nameof(PrintThing)}, x={x}, y={y} from {caller}";
}
and now you can output the task trivially.
In reality, this isn't all that different to what the compiler would generate anyway for a lambda/anonymous method with captured variables.
I would add the log into the different methods. That way you can also specialize the log messages produced by each method.

Correct way of returning a task in C#

I have a scenario wherein I need to return a method that can be awaited from the caller.
I have here my implementations, and I just want to know which of which is the correct one.
Method 1.
public class ClassA
{
public Task MyTask { get; set; }
public ClassA()
{
MyTask = MyAsyncMethod();
}
private async void MyAsyncMethod()
{
await LongProcessHere();
}
}
public class MyCaller()
{
private async void ExecuteAsync()
{
ClassA ca = new ClassA();
await ca.MyTask;
}
}
Method 2.
public class ClassA
{
public Task MyAsyncMethod()
{
return Task.Run(async()=>
{
await LongProcessHere();
});
}
}
public class MyCaller()
{
private async void ExecuteAsync()
{
ClassA ca = new ClassA();
await ca.MyAsyncMethod();
}
}
If you're asking should I expose a property or method, then that entirely depends on what the Task represents.
If the task is something done once per instance of the class, then having a Task property is appropriate. Usually in this case, the property represents something about the instance, such as "my initialization is complete" or "I am done processing".
If the task is something that you need to do multiple times, then having a Task-returning method is appropriate.
Task-returning methods are vastly more common than Task properties.
On a side note, avoid async void and don't use Task.Run unnecessarily.
The correct code would look like:
public class ClassA
{
// always return a Task from an async method
public async Task MyAsyncMethod()
{
await LongProcessHere();
}
}
public class MyCaller
{
private async Task ExecuteAsync()
{
ClassA ca = new ClassA();
await ca.MyAsyncMethod();
}
}
You do not need to use Task.Run to call an async method. Also async methods should have Task return type as opposed to void. And vice versa.
public class ClassA
{
public async Task MyAsyncMethod()
{
return await LongProcessHere();
}
}
public class MyCaller()
{
private async Task ExecuteAsync()
{
ClassA ca = new ClassA();
await ca.MyAsyncMethod();
}
}

Wrapping a Task to return a value

I feel like there is a better way to do the following and looking for other opinions.
Essentially, I am trying to utilize the async/await pattern but need to return a bool value from method to indicate what happened in the method which is causing me to wrap the Task with Task so this can be accomplished. My spidey-sense is telling me something is wrong with my implementation.
In the below example "LongRunningTask" is something I don't have control over because it is a library method that returns a Task, so something I can't change. The remainder of the flow logic could be changed. Obviously, this is just a fictional representation of my real-issue but meant to demonstrate the issue, so don't get caught-up in the hard-coded "GetData", etc...
Take a look and let me know of other options.
void Main()
{
StartApplication();
}
private async void StartApplication()
{
// This is a just fictional example passing hard-coded GetData
var didExecuteLongRunningTask = await ProcessStuff("GetData");
if (didExecuteLongRunningTask)
{
Console.WriteLine("Long running task was executed");
}
else {
Console.WriteLine("Long running task was NOT executed");
}
}
// Define other methods and classes here
private async Task<bool> ProcessStuff(string command)
{
if (command == "GetData")
{
await LongRunningTask();
return await Task<bool>.Factory.StartNew(() => true);
}
else
{
return await Task<bool>.Factory.StartNew(() => false);
}
}
private Task LongRunningTask()
{
return Task.Delay(2000);
}
Yes, you are right, you are over-complicating it. You can just do:
private async Task<bool> ProcessStuff(string command)
{
if (command == "GetData")
{
await LongRunningTask();
return true;
}
else
{
return false;
}
}
You can look at the MSDN for more information: Asynchronous Programming

What is the Task equivalent to Promise.then()?

With the addition of async / await to TypeScript using Promise(s) can look very syntactically close to Task(s).
Example:
Promise (TS)
public async myAsyncFun(): Promise<T> {
let value: T = await ...
return value;
}
Task (C#)
public async Task<T> MyAsyncFun() {
T value = await ...
return value;
}
I was wondering if the other way around, there was an equivalent to .then() for Task(s).
Example:
Promise (TS)
Promise<T> promise = ...
promise.then((result: T) => ...do something...);
I've used ContinueWith which can work if you have one or multiple Tasks running.
example:
public async Task<T> MyAsyncFun() {
T value = await ...
return value;
}
MyAsyncFun().ContinueWith(...
https://msdn.microsoft.com/en-us/library/dd270696(v=vs.110).aspx
You can create a handy extension method for task continuations to match the javascript .then function. I find it easier to use than .ContinueWith, which has its own set of pitfalls and encumbrances.
public static class TaskExtensions
{
public static async Task<TV> Then<T,TV>(this Task<T> task, Func<T,TV> then)
{
var result = await task;
return then(result);
}
}
Then you can use it like so
Task<User> userRecord = GetUserById(123)
Task<string> firstName = userRecord.Then(u => u.FirstName)

use task<string> method in overriden

I would like to know whats the ideal way to call a method that returns a Task inside an override method?
For example:
public Task<string> GetName()
{
return Task.Run(() => {
return "Foo";
});
}
In one of my methods I would just simple do this:
public async Task<string> DoSomething()
{
var res = await GetName();
return res + " rocks";
}
But now I am facing a situation where there is a method delcared like this:
public virtual string DoSomething()
{
//does something...
}
In my inheritance I need to override this method and do some stuff and call a Task method, so my first thought was to do this:
public override async Task<string> DoSomething()
{
//does something...
base.DoSomething();
var res = await GetName();
return res + " rocks";
}
This clearly isnt possible since I changed the return value from a overriden method from string to Task string...
How should I solve my problem?
(Note: I cannot modify the base class, since its not mine. Its an external libary.)
You could do this:
public override string DoSomething()
{
//does something...
base.DoSomething();
return GetName().Result;
}
Warning: this can cause a deadlock
See Don't block on async code

Categories

Resources