Home > database >  Using the result of an async Task for an event handler
Using the result of an async Task for an event handler

Time:12-20

I want to use the result of an async Task to handle an event. Other than having two member variables to denote the result of the task and whether the event has occurred or not and check those at two places, is there a better way?

For example, I order dog food on Amazon before the dog is hungry. But the dog may get hungry before the dog food is delivered from Amazon. Or the food may arrive before the dog gets hungry.

class Program
{
    private static DogFood? _Food;
    private static bool GotDogHungryEvent = false;
    public static async Task Main()
    {
        Print("Start.");
        
        var d = new Dog();
        d.Hungry = WhenDogHungry;
        
        Task.Run(async() =>
        {
            var a = new Amazon();
            _Food = await a.OrderDogFood();
            if (GotDogHungryEvent)
            {
                Print("Feeding dog on food delivery");
                d.Feed(_Food);
            }
        });
        
        Console.ReadKey();
    }

    private static void WhenDogHungry(object? sender, EventArgs e)
    {
        if (_Food == null)
        {
            Print("No food yet.");
            GotDogHungryEvent = true;
        }
        else
        {
            Print("Feeding dog on hungry event");
            (sender as Dog).Feed(_Food);
        }
    }

    public static void Print(string msg)
    {
        Console.WriteLine(DateTime.Now.ToString("HH:mm:ss.fff") ": "   msg);
    }
}

class Amazon
{
    public async Task<DogFood> OrderDogFood()
    {
        var r = new Random();
        await Task.Delay(r.Next(500, 5000));
        Program.Print("Dog food delivery from Amazon.");  
        return new DogFood();
    }
}

class Dog
{
    public event EventHandler Hungry;
    private bool IsHungry = false;

    public Dog()
    {
        Task.Run(async () =>
        {
            var r = new Random();
            await Task.Delay(r.Next(500, 5000));
            Program.Print("Dog is hungry.");
            IsHungry = true;
            Hungry(this, null);
        });
    }

    public void Feed(DogFood food)
    {
        if(!IsHungry)
        {
            throw new ApplicationException("Dog not hungry.");
        }
    }
}

class DogFood
{
}

CodePudding user response:

You have a state: dog is hungry. You want to ideally order (event 1) and have food delivered (event 2) prior to the state becoming true.

There's no better way than keeping track of the state in a (nullable) bool and do the same for if food is ordered. If dog becomes hungry and foodIsOrdered = true, then you don't do anything. Then when food arrives, you can call a FeedDog() method.

  •  Tags:  
  • c#
  • Related