Being developers, we should all be quite familiar with events. Most developers have been creating events since we started writing code. In fact, if you have even dropped a button control on a form and double-clicked the button to create the method that handles the click of the button, you have created an event. In .NET, we can declare events using the event
keyword, publish to the event by invoking it, and subscribe to that event by adding a handler to the event. We therefore have the following operations:
With Rx, we have a similar structure where we declare a data stream, publish data to that stream, and subscribe to it.
First, we will see how an event works in C#. We will then see the working of an event using Rx and, in doing so, highlight the differences.
DotNet
. To this class, add a property called AvailableDatatype
:public class DotNet { public string AvailableDatatype { get; set; } }
types
. Basically, this is just a delegate and will receive some value, in our case, the available .NET data types:class Program { // Static action event static event Action<string> types; static void Main(string[] args) { } }
void Main
, create a List<DotNet>
class called lstTypes
. Inside this list, add several values of type DotNet
class. Here, we will just add hardcoded data of some of the data types in .NET:List<DotNet> lstTypes = new List<DotNet>(); DotNet blnTypes = new DotNet(); blnTypes.AvailableDatatype = "bool"; lstTypes.Add(blnTypes); DotNet strTypes = new DotNet(); strTypes.AvailableDatatype = "string"; lstTypes.Add(strTypes); DotNet intTypes = new DotNet(); intTypes.AvailableDatatype = "int"; lstTypes.Add(intTypes); DotNet decTypes = new DotNet(); decTypes.AvailableDatatype = "decimal"; lstTypes.Add(decTypes);
lstTypes
list by adding the line types(lstTypes[i].AvailableDatatype);
:types += x => { Console.WriteLine(x); }; for (int i = 0; i <= lstTypes.Count - 1; i++) { types(lstTypes[i].AvailableDatatype); } Console.ReadLine();
class Program { // Static action event static event Action<string> types; static void Main(string[] args) { List<DotNet> lstTypes = new List<DotNet>(); DotNet blnTypes = new DotNet(); blnTypes.AvailableDatatype = "bool"; lstTypes.Add(blnTypes); DotNet strTypes = new DotNet(); strTypes.AvailableDatatype = "string"; lstTypes.Add(strTypes); DotNet intTypes = new DotNet(); intTypes.AvailableDatatype = "int"; lstTypes.Add(intTypes); DotNet decTypes = new DotNet(); decTypes.AvailableDatatype = "decimal"; lstTypes.Add(decTypes); types += x => { Console.WriteLine(x); }; for (int i = 0; i <= lstTypes.Count - 1; i++) { types(lstTypes[i].AvailableDatatype); } Console.ReadLine(); } }
Subject
of string
. You might also need to add the System.Reactive.Subjects
namespace to your project as Subjects
live in this separate namespace:class Program { static Subject<string> obsTypes = new Subject<string>(); static void Main(string[] args) { } }
DotNet
, we used +=
to wire up an event handler. This time round, we will use Subscribe
. This is the IObservable
portion of the code. After you have added this, raise the event using the OnNext
keyword. This is the IObserver
portion of the code. Therefore, as we loop through our list, we will call OnNext
to pump out the values to the subscribed IObservable
interface:// IObservable obsTypes.Subscribe(x => { Console.WriteLine(x); }); // IObserver for (int i = 0; i <= lstTypes.Count - 1; i++) { obsTypes.OnNext(lstTypes[i].AvailableDatatype); } Console.ReadLine();
class Program { static Subject<string> obsTypes = new Subject<string>(); static void Main(string[] args) { List<DotNet> lstTypes = new List<DotNet>(); DotNet blnTypes = new DotNet(); blnTypes.AvailableDatatype = "bool"; lstTypes.Add(blnTypes); DotNet strTypes = new DotNet(); strTypes.AvailableDatatype = "string"; lstTypes.Add(strTypes); DotNet intTypes = new DotNet(); intTypes.AvailableDatatype = "int"; lstTypes.Add(intTypes); DotNet decTypes = new DotNet(); decTypes.AvailableDatatype = "decimal"; lstTypes.Add(decTypes); // IObservable obsTypes.Subscribe(x => { Console.WriteLine(x); }); // IObserver for (int i = 0; i <= lstTypes.Count - 1; i++) { obsTypes.OnNext(lstTypes[i].AvailableDatatype); } Console.ReadLine(); } }
In Rx, we can declare an event stream with the Subject
keyword. So, we have a source of events that we can publish to using OnNext
. To see those values in the console window, we subscribed to the event stream using Subscribe
.
Rx allows you to have objects that are just publishers or just subscribers. This is because the IObservable
and IObserver
interfaces are in fact separate. Also, note that in Rx, the observables can be passed as parameters, returned as results, and stored in variables, which makes them first class:
Rx also allows you to specify that the event stream is completed or that an error occurred. This really sets Rx apart from events in .NET. Also, it is important to note that including the System.Reactive.Linq
namespace in your project allows developers to write queries over the Subject
type because a Subject
is an IObservable
interface:
This is another feature that sets Rx apart from the events in .NET.