Events versus observables

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:

  • Declare
  • Publish
  • Subscribe

With Rx, we have a similar structure where we declare a data stream, publish data to that stream, and subscribe to it.

Getting ready

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.

How to do it…

  1. In your console application, add a new class called DotNet. To this class, add a property called AvailableDatatype:
    public class DotNet
    {
        public string  AvailableDatatype { get; set; }
    }
  2. In the main program class, add a new static action event called 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)
        {
        
        }
    }
  3. Inside 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);
  4. Our next task is to subscribe to this event with an event handler that is simply outputting the value of x to the console window. We will then raise the event each time we loop through our 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();

    Note

    In reality, before raising an event, we should always check that the event isn't null. Only after this check should we raise the event. For brevity, we have not added this check before raising the event.

  5. When you have added all the code from step 1 to step 4, your console application should look like this:
    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();
        }
    }
  6. Running your application will set our list with values and then raise the event created to output the values of the list to the console window:
    How to do it…
  7. Let's see the working of events using Rx. Add a static 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)
        {
        
        }
    }
  8. After the code that created the list of 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();
  9. When you have completed adding all the code, your application should look like this:
    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();
        }
    }
  10. When you run your application, you will see the same items output to the console window as earlier:
    How to do it…

How it works…

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:

How it works…

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:

How it works…

This is another feature that sets Rx apart from the events in .NET.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.191.234.150