user5448022
user5448022

Reputation:

Count number of subscribers to a publisher from a separate class? How to get reference to InvocationList of Handler from a different class?

I have a C# project where there are a number of events. So, there a number of publisher and a number of subscribers that subscribe to that event. What I want is to keep a count of subscribers to each of the publishers.

For simplicity, I have created a basic scenario here. In this example, I want to count the number of subscribers to each publisher in Class EventsCounter. I have a number of questions here.

  1. Is there anyway to know how many events are there in the project or will I have to list them manually in Class EventsCounter?
  2. How do I get reference to the handler in each Events?
  3. Is there any way to do this more efficiently?

Here, I could use the InvocationList but I could not reference the handler from a different class. e.g. Publisher.Foo gave me an error.

    using System;

    namespace EventTest
    {
        class Program
        {
            static void Main(string[] args)
            {
                GenerateEvents ge = new GenerateEvents();
            }
        }

        public class EventsCounter
        {
            //need to count all events and corresponding subscribers here
        }

        public class GenerateEvents
        {
            public GenerateEvents()
            {
                Publisher publisher = new Publisher();
                Subscriber subscriber1 = new Subscriber();
                Subscriber subscriber2 = new Subscriber();

                publisher.Foo += subscriber1.FooHandler;
                publisher.Foo += subscriber2.FooHandler;
                publisher.RaiseFoo();

                publisher.Foo -= subscriber1.FooHandler;
                publisher.Foo -= subscriber2.FooHandler;
                publisher.RaiseFoo();

                Console.Read();
            }
        }

        public class Publisher
        {
            public event EventHandler Foo;
            int count = 0;

            public void RaiseFoo()
            {
                Console.WriteLine("Raising Foo");
                EventHandler handler = Foo;

                if (handler != null)
                {
                    foreach (EventHandler subscriber in handler.GetInvocationList())
                    {
                        count++;
                        subscriber(this, EventArgs.Empty);
                    }
                    Console.WriteLine("The count is {0}", count);
                }
                else
                {
                    Console.WriteLine("No subscribers!");
                }
            }
        }

        public class Subscriber
        {
            public void FooHandler(object sender, EventArgs e)
            {
                Console.WriteLine("Subscriber Called");
            }
        }
    }

Upvotes: 3

Views: 242

Answers (1)

Abdullah Nehir
Abdullah Nehir

Reputation: 1047

You might declare a property of type Event. This way, you can track subscription to and removal from your event.
Also, you can enumerate through subscribed handlers by calling your event's GetInvocationList() method. I demonstrated this within the publisher's EnumerateSubscribers() method.
Below code is a demonstration:

using System;

namespace MyApp
{
    class Program
    {
        static void Main(string[] args)
        {
            var p = new Publisher();
            var s1 = new Subscriber("first");
            s1.Subscribe(p);
            p.RaiseFoo(null, null);
            var s2 = new Subscriber("second");
            s2.Subscribe(p);
            p.RaiseFoo(null, null);
            p.EnumerateSubscribers();
            s1.Unsubscribe(p);
            p.RaiseFoo(null, null);
            s2.Unsubscribe(p);
            Console.ReadKey();
        }
    }

    public class Subscriber
    {
        public string Name { get; set; }

        public Subscriber(string name)
        {
            this.Name = name;
        }

        public void Subscribe(Publisher p)
        {
            p.Foo += this.HandleFoo;
        }

        public void Unsubscribe(Publisher p)
        {
            p.Foo -= this.HandleFoo;
        }

        private void HandleFoo(object sender, EventArgs e)
        {
            Console.WriteLine(this.Name + " is called");
        }

        public override string ToString()
        {
            return this.Name;
        }
    }

    public class Publisher
    {
        private int count;
        private EventHandler _foo;

        public void RaiseFoo(object sender, EventArgs e)
        {
            if (_foo != null)
            {
                _foo(sender, e);
            }
        }

        public void EnumerateSubscribers()
        {
            if (_foo != null)
            {
                foreach (var item in _foo.GetInvocationList())
                {
                    Console.WriteLine("Subscriber object:" + item.Target?.ToString());
                }
            }
        }

        public event EventHandler Foo
        {
            add
            {
                _foo += value;
                Console.WriteLine("Count:" + ++count);
            }

            remove
            {
                _foo -= value;
                Console.WriteLine("Count:" + --count);
            }
        }
    }


}

Upvotes: 1

Related Questions