Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is alternative of Events and Delegates in c#?

I have been recently asked in an interview like if we don't have Events and Delegates how can we acheive the same functionality of Publisher and Subsriber model without Delegate and Events.

Can you please explain me with an example it will be really helpful and will help others too?

like image 594
Rahul Sharma Avatar asked May 05 '17 08:05

Rahul Sharma


People also ask

Can we use events without delegates?

Yes, you can declare an event without declaring a delegate by using Action. Action is in the System namespace.

What is difference between event and delegate in C?

A delegate specifies a TYPE (such as a class , or an interface does), whereas an event is just a kind of MEMBER (such as fields, properties, etc). And, just like any other kind of member an event also has a type. Yet, in the case of an event, the type of the event must be specified by a delegate.

What is the difference between events and multicast delegates?

Multicast delegates help to invoke multiple callbacks. Events encapsulate delegate and implement publisher and subscriber model.

How delegates and events are related?

Delegate is a type that defines a signature and holds a reference of method whose signature matches with the delegate. Event is a notification raised by an object to signal the occurrence of an action. Delegate is associated with the event to hold a reference of a method to be called when the event is raised.


2 Answers

Instead of using a delegate, the subscriber can implement an interface ISubscriber that has a method SomeEvent, and pass itself to the publisher (to a method with a signature Subscribe(ISubscriber subscriber)). The publisher then will store this reference to the subscriber and call subscriber.SomeEvent when necessary.

Something like:

public interface ISubscriber
{
    void SomeEvent(object publisher, object data);
}

public class SomePublisher
{
    private readonly HashSet<ISubscriber> subscribers = new HashSet<ISubscriber>();

    public void Subscribe(ISubscriber subscriber)
    {
        subscribers.Add(subscriber);
    }

    public void Unsubscribe(ISubscriber subscriber)
    {
        subscribers.Remove(subscriber);
    }

    public void DoSomething()
    {
        // Do something

        // Then

        foreach (var subscriber in subscribers)
        {
            object data = "Some data";
            subscriber.SomeEvent(this, data);
        }
    }
}

Note that this model of publisher/subscriber isn't limited to a single "event": ISubscriber could have multiple methods corresponding on multiple "events". The only problem is that if there are multiple "events" in the interface, the subscriber must "subscribe" to all the events (must have methods for all the events). So if there are an OnAdded and an OnRemoved methods in ISubscriber, classes implementing ISubscriber must have both methods (clearly they could be empty stubs that do nothing)

I'll add that, in the end, delegates can be "simulated" by interfaces with a single method, and events can be considered to be List<somedelegatetype>, so events can be considered to be List<ISomeInterface>. Java for example doesn't have delegates and uses interfaces with a single method in lieu of them (see for example Java Delegates?)

like image 109
xanatos Avatar answered Oct 28 '22 21:10

xanatos


The simplest implementation of Publisher / Subscriber:

// Universal interface for all subscribers:
public interface ISubscriber<TEvent>
{
    void HandleEvent(object sender, TEvent ev);
}

// Universal publisher, can be used directly with generic argument
public class Publisher<TEvent>
{
    protected ISet<ISubscriber<TEvent>> _subscribers = new HashSet<ISubscriber<TEvent>>();

    public void Publish(TEvent ev)
    {
        foreach (var sub in _subscribers)
        {
            sub.HandleEvent(this, ev);
        }
    }

    public void Subscribe(ISubscriber<TEvent> subscriber)
    {
        _subscribers.Add(subscriber);
    }

    public void Unsubscribe(ISubscriber<TEvent> subscriber)
    {
        _subscribers.Remove(subscriber);
    }
}

// Or can be inherited to encapsulate any sort of logic
public class RandomIntegerPublisher : Publisher<int>
{
    private readonly Random _random = new Random();

    public void Publish()
    {
        Publish(_random.Next());
    }
}

// Example subscriber, which can even implement multiple ISubscriber interfaces
public class ExampleSubscriber : ISubscriber<int>, ISubscriber<string>
{
    public void HandleEvent(object sender, int ev)
    {
        Console.WriteLine($"Integer event: {ev}");
    }

    public void HandleEvent(object sender, string ev)
    {
        Console.WriteLine($"String event: {ev}");
    }
}

void Main()
{
    var subscriber = new ExampleSubscriber();

    var randomIntegerPublisher = new RandomIntegerPublisher();
    randomIntegerPublisher.Subscribe(subscriber);

    var stringPublisher = new Publisher<string>();
    stringPublisher.Subscribe(subscriber);

    randomIntegerPublisher.Publish();
    randomIntegerPublisher.Publish();
    randomIntegerPublisher.Publish();
    stringPublisher.Publish("Hello World!");
}

Outputs:

Integer event: 1547238746
Integer event: 844169413
Integer event: 673377792
String event: Hello World!

It is not very flexible since uses OOP for publisher / subscriber pattern implementation and required classes to be created for every type of publisher and every specific subscriber, but it shows the main idea, which can be improved by yourself in many ways.

like image 32
Yeldar Kurmangaliyev Avatar answered Oct 28 '22 19:10

Yeldar Kurmangaliyev