Showing posts with label event. Show all posts
Showing posts with label event. Show all posts

August 26, 2021

Exposing C# Events using Reactive Extensions

There is a way to convert existing C# events to an IObservable<>. There is a good article here on this

public class SimpleEventSource
{
  public event EventHandler<MyEventArgs> SimpleEvent;
     
  // Normally this would be private (event is triggered internally) 
  // but for test purposes we make it public
  public void FireSimpleEvent(MyEvent myevent)
  {
    EventHandler<MyEventArgs> tmp = SimpleEvent;
    if (tmp != null)
    {
      tmp(this, new MyEventArgs(myEvent));
    }
  }   
 
  // This returns an IObservable (effectively an event pulisher)
  public IObservable<EventPattern<MyEventArgs>> MyEventPublisher
  {
    get
    {       // To consume SimpleEvent as an IObservable:
        IObservable<EventPattern<MyEventArgs>> eventAsObservable = Observable.
            FromEventPattern<MyEventArgs>(
              ev => SimpleEvent += ev,
              ev => SimpleEvent -= ev);
        return eventAsObservable;
    }
  }

}

Note that MyEventArgs is something derived from EventArgs that allows access to the "MyEvent" instance, see below. Here is a tester:

public void TestSimpleEventSource()
{
    var ses = new SimpleEventSource();
    ses.FireSimpleEvent(new MyEvent("1st event")); // This one is missed

    using (var subscription = ses.MyEventPublisher.Subscribe(
        ev => Console.WriteLine(ev.EventArgs.MyEvent.Text + " fired")))
    {
        ses.FireSimpleEvent(new MyEvent("2nd event"));
        ses.FireSimpleEvent(new MyEvent("3rd event"));               
    }

    Console.WriteLine("Subscription cancelled");
}
and the output
2nd event fired
3rd event fired
Subscription cancelled

Replacing C# Events using Reactive Extensions

Lets take this one step further, and completely replace the C# event with a reactive style event publisher

internal class SimpleEventSource
{
    private Subject<MyEvent> _myEventSubject = new Subject<MyEvent>();

    public IObservable<MyEvent> MyEventPublisher => this._myEventSubject.AsObservable();

    public void FireSimpleEvent(MyEvent myEvent) => this._myEventSubject.OnNext(myEvent);
}
And the same test but using this class:
public void TestSimpleEventSource2()
{
    var ses = new SimpleEventSource2();
    ses.FireSimpleEvent(new MyEvent("1st event"));

    using (var subscription = ses.MyEventPublisher.Subscribe(
        ev => Console.WriteLine(ev.Text + " fired")))
    {
        ses.FireSimpleEvent(new MyEvent("2nd event"));
        ses.FireSimpleEvent(new MyEvent("3rd event"));
    }

    Console.WriteLine("Subscription cancelled");
}

Here is the code for the simple event classes if it makes things clearer

public class MyEvent
{
    public MyEvent(string text)
    {
        Text = text;
    }
    public string Text { get; private set; }
}

public class MyEventArgs : EventArgs
{
    public MyEventArgs(MyEvent myEvent)
        : base()
    {
        MyEvent = myEvent;
    }
    public MyEvent MyEvent { get; private set; }
}

August 19, 2021

C# Event Aggregators

Did some research into event aggregators. They are a great way to allow events to be fired betwen classes without the classes being tightly coupled, in other words without either class having to know about the other. Standard C# events make the classes tighly coupled, the listener needs to know about the firer. Sometimes with standard c# events, an event will need to be transmitted through an intermediate sequence of objects just to reach the target recipient, this is very cumbersome and laborious. Event aggregators completely decouple the event publishers from the event subscribers as long as both subscriber and publisher objects can access the event aggregator their is no need for intermediate objects to relay the events

Would make an excellent start for a simulator which has both hardware and software events occuring, an event aggregator could be used to input events to the system. As it is completely decoupled from the system, it would be easy to emulate firing these software events say from a GUI for emulation purposes, and also easy to connect to real hardware to populate those same software events.

I found several links that use a Reactive Extensions to implement an Event Aggregator. Using the Reactive Extensions the code to implement an aggregator is very small and compact.

  1. https://mikebridge.github.io/post/csharp-domain-event-aggregator
It is also a great example in the usage of Reactive Extensions. Currently I have combined them into this form:

using System.Reactive.Linq; // You'll need the Reactive nuget package
using System.Reactive.Subjects;
...

public interface IRxEventAggregator : IEventAggregator, IDisposable
{
    /// <summary>
    ///  Use this method to apply RX (LINQ style) expressions on
    ///  the events before subscribing
    /// </summary>
    /// <typeparam name="TEvent"></typeparam>
    /// <returns></returns>
    IObservable<TEvent> GetEventsObservable<TEvent>();
}

public interface IEventAggregator
{
    IDisposable Subscribe<T>(Action<T> action);
    void Publish<T>(T @event);
}


/// <summary>
/// An EventAggregator that is based on reactive extensions and supports
/// </summary>
public class RxEventAggregator
    : IRxEventAggregator
{
    readonly Subject<object> _subject = new Subject<object>();

    // Use this method to use RX (LINQ style) expressions
    // on the events before subscribing
    public IObservable<TEvent> GetEventsObservable<TEvent>()
    {
        return _subject.OfType<TEvent>().
            AsObservable();
    }

    public IDisposable Subscribe<T>(Action<T> action)
    {
        return GetEventsObservable<T>().
            Subscribe(action);
    }

    public void Publish<TEvent>(TEvent sampleEvent)
    {
        _subject.OnNext(sampleEvent);
    }

    #region IDisposable

... // See below

    #endregion
}

Generally an Event Aggregator lives throughout the life of your software so it really does not need disposing of. You could remove the Dispose code completely. For that reason I list it here just for reference:

    #region IDisposable

    bool _disposed;

    ~RxEventAggregator()
    {
        Dispose(false);
         // Useful for detecting memory leaks
        Debug.Assert(false, nameof(RxEventAggregator) + 
            " was not disposed of");
    }

    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this); 
    }

    protected virtual void Dispose(bool disposing)
    {
        if (_disposed) return;

        _subject.Dispose();
        _disposed = true;
    }

    #endregion

Here's another event aggregator:

// When there are a lot of events with lots of subscribers
public class RxEventAggregator
: IRxEventAggregator
{
    private volatile ConcurrentDictionary<Type, object> _subjects
        = new ConcurrentDictionary<Type, object>();

    // Use this method to use RX (LINQ style) expressions
    // on the events before subscribing
    public IObservable<TEvent> GetEventsObservable<TEvent>()
    {
        Trace.Assert(!_disposed, "Trying to access a disposed EventAggregator");
        var subject =
            (ISubject<TEvent>)_subjects.GetOrAdd(typeof(TEvent),
                        _ => new Subject<TEvent>());
        return subject.AsObservable();
    }

    public IDisposable Subscribe<T>(Action<T> action)
    {
        Trace.Assert(!_disposed, "Trying to access a disposed EventAggregator");
        return GetEventsObservable<T>().
            Subscribe(action);
    }

    public void Publish<TEvent>(TEvent sampleEvent)
    {
        Trace.Assert(!_disposed, "Trying to access a disposed EventAggregator");
        if (_subjects.TryGetValue(typeof(TEvent), out var subject))
        {
            ((ISubject<TEvent>)subject)
                .OnNext(sampleEvent);
        }
    }

    // If your Aggregator is a life (of the application) long one you can simply not bother with disposing of it
    #region IDisposable 

    bool _disposed;

    ~RxEventAggregator2()
    {
        Debug.Assert(false, nameof(RxEventAggregator2) + " was not disposed of"); // Useful for detecting memory leaks
    }

    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);  // no need to call finalizer now
    }

    protected virtual void Dispose(bool disposing)
    {
        if (_disposed) return;

        _disposed = true;
        // Make them unaccessible
        var hiddenSubjects = Interlocked.Exchange(ref _subjects, new ConcurrentDictionary<Type, object>());
        // Then dispose of them
        foreach (var subject in hiddenSubjects.Values.Cast<IDisposable>())
        {
            subject.Dispose();
        }

    }

    #endregion
}

August 2, 2012

Generic Event Firer


Here is the common .NET pattern for firing some event
// Here is the event
public event EventHandler<ReminderEventArgs> ReminderOccured;
...
// And to fire it
EventHandler<ReminderEventArgs> reminderOccured = this.ReminderOccured;
if (reminderOccured != null)
{
    reminderOccured(this, new ReminderEventArgs { Reminder = reminder });
}

This is a common pattern so a helper class to tidy this up might be of some use:
public static class EventFirer
{
    public static void FireEvent<TEventArgs>(object firer, 
        EventHandler<TEventArgs> eventToFire, TEventArgs eventargs)
        where TEventArgs : EventArgs
    {
        EventHandler<TEventArgs> eventToFireReference = eventToFire;
        if (eventToFireReference != null)
        {
            eventToFireReference(firer, eventargs);
        }
    }

    public static void FireEvent(object firer, EventHandler eventToFire, 
        EventArgs eventargs)
    {
        EventHandler eventToFireReference = eventToFire;
        if (eventToFireReference != null)
        {
            eventToFireReference(firer, eventargs);
        }
    }
}
With this class firing the event becomes:
EventFirer.FireEvent<ReminderEventArgs>(this, 
    this.ReminderOccured, 
    new ReminderEventArgs { Reminder = reminder });

May 14, 2010

Events In C#

Look here: How to: Implement Events in Your Class - A good beginners guide.
and here: C# events vs. delegates - Good detailed explanation of events and how they differ from delegates

Implementing the event in Your Publisher Class

Step 1 (Optional): Define your custom "EventArgs" class
public class SomethingChangedEventArgs : EventArgs
{
...
}
The following steps take place in the event publisher class
class SomethingChangedEventPublisher
{
Step 2: Expose your custom EventHandler
  public event EventHandler<SomethingChangedEventArgs> SomethingChanged; // for events with custom arguments
  public event EventHandler SomethingChanged; // otherwise use this for standard events
Step 3: Define an event publishing helper method (this is agood practice)
  void PublishSomethingChangedEvent(SomethingChangedEventArgs ea)
  {
    EventHandler<SomethingChangedEventArgs> eh = this.SomethingChanged
    if (eh != null)
      eh(this, ea);
  }
Step 4: Publish/Fire/Trigger the event in the appropriate places
  ...
  PublishSomethingChangedEvent(this, new SomethingChangedEventArgs(...));
  
  ...
}

Subscribing to the event in the Listener/Observer/Subscriber Class

The following steps take place in the event observer/subscriber class
class SomethingChangedEventSubscriber
{
Step 5: Subscribe to the event
  // VS Intellisense will do most of the work for you here!
  SomethingChangedEventSource.SomethingChanged += new EventHandler<SomethingChangedEventArgs>(OnSomethingChanged);
...
Step 6: Handle the event
  // The method where the SomethingChangedEvent is processed 
  private void OnSomethingChanged(object sender, SomethingChangedEventArgs eargs)
  {
    // SomethingChanged detected, now do something with it here
  }
...
Step 7: Unsubscribe to the event. This is in my experience the biggest cause of memory leaks in C# programs
  // VS Intellisense will do most of the work for you here!
  SomethingChangedEventSource.SomethingChanged -= new EventHandler<SomethingChangedEventArgs>(OnSomethingChanged);
  
...
}
Alternatively, use an inline delegate to handle the event
SomethingChangedEventSource.SomethingChanged += delegate (object sender, SomethingChangedEventArgs e)
{
  ...
};
But there is a danger to doing this see here
Also in Windows Forms programs events often lead to memory leaks as the events were never detached seehere
Note that the event source is called the "Event Publisher", ie. it is the class containg the event definition. The event target or "Subscriber" is the object attaching a delegate to the event. Be careful with C# events and the Garbage Collection of unreferenced objects. A C# event publisher holds a reference to the subscriber so the Subscriber cannot be disposed of until that event is detached (or there is no longer a reference to either the publisher or subscriber). This also means that if the subscriber has a Dispose event, you cannot rely on the system to invoke it in a GC round until that event is detached. If you attach a subscriber on to the event of a publisher, ensure it is detached