Search code examples
c#eventsdesign-patterns.net-2.0

Listen to specific events of inherited classes


Suppose we have the following class structure:

public class Fruit
{
    public event EventHandler<RipeEventArgs> Ripe;
}

public class Apple:Fruit
{
    public event EventHandler<FallEventArgs> FallFromTree;
}

public class Farm
{
    List<Fruit> fruits;
}

public class Farmer
{
    private Farm myFarm;

    public Farmer()
    {
        // listen to all FallFromTree events coming from the farm
        myFarm.WHAT += AppleFallen;
    }

    public void AppleFallen(object sender, FallEventArgs e) {}
}

Question: How do I make sure that the farmer can listen to all FallFromTree events from any apple on the farm and any apple that will be created in the future?

I was thinking of bubbling events separate, but that would mean that the Farm should define each event that is also covered by Apple. The problem is that I will create a lot of different fruits with different events and it is important that some special farmer can listen to only specific events that come from the farm. So defining every new kind of event in the Farm doesn't seem like a solution to me.


Solution

  • Just let the Farm know about the Farmer rather than the Farmer know about the Farm.

    public class Fruit
    {
        public event EventHandler<RipeEventArgs> Ripe;
    }
    
    public class Apple:Fruit
    {
        public event EventHandler<FallEventArgs> FallFromTree;
    }
    
    public class Farm
    {
        List<Fruit> fruits;
        Farmer farmer;
    
        public Farm(Farmer farmer)
        {
            this.farmer = farmer;
        }
    
        public void AddFruit(Fruit fruit)
        {
            farmer.RegisterForEvents(fruit);
            fruits.Add(fruit);
        }
    }
    
    public class Farmer
    {
        private Farm myFarm;
    
        public Farmer()
        {
    
        }
    
        public virtual void RegisterForEvents(Fruit fruit)
        {
           //Farmer decides what events it is interested in: can override in derived classes
           if(fruit is Apple)
           {
               ((Apple)fruit).FallFromTree += AppleFallen;
           }
        }
    
        public void AppleFallen(object sender, FallEventArgs e) {}
    }
    

    The fruit is Apple clause isn't ideal but I think the only thing you can do there is either implement double-dispatch or have different methods on Farmer for each type of Fruit.