Super-Simple Example of C# Observer/Observable with Delegates

Super-simple example of C# observer/observable with delegates

The observer pattern is usually implemented with events.

Here's an example:

using System;

class Observable
{
public event EventHandler SomethingHappened;

public void DoSomething() =>
SomethingHappened?.Invoke(this, EventArgs.Empty);
}

class Observer
{
public void HandleEvent(object sender, EventArgs args)
{
Console.WriteLine("Something happened to " + sender);
}
}

class Test
{
static void Main()
{
Observable observable = new Observable();
Observer observer = new Observer();
observable.SomethingHappened += observer.HandleEvent;

observable.DoSomething();
}
}

See the linked article for a lot more detail.

Note that the above example uses C# 6 null-conditional operator to implement DoSomething safely to handle cases where SomethingHappened has not been subscribed to, and is therefore null. If you're using an older version of C#, you'd need code like this:

public void DoSomething()
{
var handler = SomethingHappened;
if (handler != null)
{
handler(this, EventArgs.Empty);
}
}

Implementing observer pattern with events

Events are an implementation of the observer pattern.

An event is implemented as a list of methods to be called when the vent is raised.

Delegates are method references: in contrast to Java, C# offers a way to refer to a method.

It's not a priori better to use events than implement the observer pattern oneself. But events offer a quite generic way to do it, and are in many cases highly optimized for the task, thus give a more efficient and convenient way organize this.

A delegate is defined by the signature of the expected method. For instance with:

public delegate void FooMethod (Bar x, Baz y);

You define a delegate for void methods given a Bar and a Baz. So if you have an instance of the following class:

public class Qux {

public void Method (Bar x, Baz y) {
//do something
return null;
}

}

Then you can refer to the method:

Qux q = new Qux();
FooMethod fm = q.Method;

An event is thus a list of delegates with the same signature:

You define an event as:

private event FooMethod SomeEvent;

You can add delegates (listeners) by using the += operator:

SomeEvent += q.Method;

remove the delegate by the -= operator and call the event with:

SomeEvent(new Bar(), new Baz());

As if you call a single method that does the dispatching.

By calling the event, all the registered delegates will be called, in the order of registration.

Note: By calling SomeEvent(new Bar(), new Baz()); this does not mean every delegate receives new instances: the instances are constructed first and shared over all delegate calls.

Conclusion: I think the C# designers did a good job introducing observer patterns since the programmer is no longer responsible to program it correctly his/herself. Furthermore the events are easy to understand and use convenient syntax. In special situations however programmers can be required to implement an observer him/herself. But these are very rare occasions.

How you would you describe the Observer pattern in beginner language?

The best example I can come up with is that of a mailing list (as an example).

You, the observer, subscribe to a mailing list and you observe the list. When you are no longer interested in the list, you unsubscribe.

This concept is the observer pattern. Two or more classes are involved. One or more class, subscribes to a publisher class (there are different names) and then the first class (and every subscribing class) will get notified when ever the publisher desires.

This is how I explained it to my wife, who often listens to my rantings about programming and design theory. It made sense to her. I realize this might be too simple for you but is a good start...

Regards,

Frank

Observer pattern in C# / how to make a Form an observer

Short Answer: look at first answer to this question: Super-simple example of C# observer/observable with delegates

I understand you wanting to try and implement it yourself but delegates and events are really the natural fit here (and are in fact an implemention of the observer pattern built into c#).

If still want to do it yourself I would recommend using interfaces instead of abstract/concrete classes.

public interface ISubject
{
void AttachObserver(IObserver observer);
void DetachObserver(IObserver observer);

void NotifyObservers(CommonNotification Notification);
}

public interface IObserver
{
void OnNotify(CommonNotification Notification);
}

Your form could then implement IObserver (or ISubject or both!!).

public class MyForm : Form, IObserver
{
...
}

Implementing just the opposite of the observer pattern (C#) - Parent monitoring all childs

What problem are you trying to solve? The Observer pattern is about isolating observees from the observer and vice versa, giving you the flexibility to add new observees without modifying your observer. Just provide a delegate in the parent process for child processes to fire off when an interesting event occurs. It's a pretty classic fit for the Observer pattern, so I don't really get what you think is so 'opposite' of your scenario.

You should probably pass in the delegate when starting your child processes and let them hang on to the reference. That way, you won't have to provide a mechanism for child processes to find the parent process, either through the OS, through a Singleton or through global variables, any of which options tend to defeat unit testability.

As a side note, when the Observer pattern was first described, mainstream OO languages didn't have delegate-like functionality. In essence, delegates are Observers incorporated in the C# language and .NET platform.

Super simple example for a Delegate-Event in c#.net?

This is a simple implementation of a class that exposes an event.

public class ChangeNotifier
{
// Local data
private int num;

// Ctor to assign data
public ChangeNotifier(int number) { this.num = number; }

// The event that can be subscribed to
public event EventHandler NumberChanged;

public int Number
{
get { return this.num; }
set
{
// If the value has changed...
if (this.num != value)
{
// Assign the new value to private storage
this.num = value;

// And raise the event
if (this.NumberChanged != null)
this.NumberChanged(this, EventArgs.Empty);
}
}
}
}

This class may be used something like as follows:

public void SomeMethod()
{
ChangeNotifier notifier = new ChangeNotifier(10);

// Subscribe to the event and output the number when it fires.
notifier.NumberChanged += (s, e) => Console.Writeline(notifier.Number.ToString());

notifier.Number = 10; // Does nothing, this is the same value
notifier.Number = 20; // Outputs "20" because the event is raised and the lambda runs.
}

Regarding control flow, execution flows into SomeMethod(). We create a new ChangeNotifier and thus call its constructor. This assigns the value of 10 to the private num member.

We then subscribe to the event using the += syntax. This operator takes a delegate on the right hand side (in our case, that delegate is a lambda) and adds it to the collection of delegates on the event. This operation doesn't execute any code that we've written in the ChangeNotifier. It can be customized through the add and remove methods on the event if you'd like, but there's rarely a need to do that.

Then we perform a couple simple operations on the Number property. First we assign 10, which runs the set method on the Number property with value = 10. But the num member is already valued at 10, so the initial conditional evaluates to false and nothing happens.

Then we do the same thing with 20. This time the value is different, so we assign the new value to num and fire the event. First we verify that the event is not null. It's null if nothing has subscribed to it. If it's not null (ie, if something is subscribed to it), we fire it using the standard method/delegate syntax. we simply call the event with the event's arguments. This will call all methods that have subscribed to the event, including our lambda that will perform a Console.WriteLine().


Henrik has successfully nitpicked the potential race condition that exists if one thread can be in Number's setter while another thread is unsubscribing a listener. I don't consider that a common case for someone who doesn't yet understand how events work, but if you're concerned about that possibility, modify these lines:

if (this.NumberChanged != null)
this.NumberChanged(this, EventArgs.Empty);

to be something like this:

var tmp = this.NumberChanged;
if (tmp != null)
tmp(this, EventArgs.Empty);

Observer pattern in c++/cli for mixed managed/unmanaged

You are trying to use C# syntax. Events work a little differently in C++/CLI, they have a raise accessor in addition to the add and remove accessor. In other words, a method that fires the event. The compiler auto-generates one if you don't provide your explicit version it. That makes raising the event very simple:

void DoSomething() {
SomethingHappened(this, System::EventArgs::Empty);
}

IObserver and IObservable in C# for Observer vs Delegates, Events

Here's a modification of MSDN example to fit your framework:

    public struct Message
{
string text;

public Message(string newText)
{
this.text = newText;
}

public string Text
{
get
{
return this.text;
}
}
}

public class Headquarters : IObservable<Message>
{
public Headquarters()
{
observers = new List<IObserver<Message>>();
}

private List<IObserver<Message>> observers;

public IDisposable Subscribe(IObserver<Message> observer)
{
if (!observers.Contains(observer))
observers.Add(observer);
return new Unsubscriber(observers, observer);
}

private class Unsubscriber : IDisposable
{
private List<IObserver<Message>> _observers;
private IObserver<Message> _observer;

public Unsubscriber(List<IObserver<Message>> observers, IObserver<Message> observer)
{
this._observers = observers;
this._observer = observer;
}

public void Dispose()
{
if (_observer != null && _observers.Contains(_observer))
_observers.Remove(_observer);
}
}

public void SendMessage(Nullable<Message> loc)
{
foreach (var observer in observers)
{
if (!loc.HasValue)
observer.OnError(new MessageUnknownException());
else
observer.OnNext(loc.Value);
}
}

public void EndTransmission()
{
foreach (var observer in observers.ToArray())
if (observers.Contains(observer))
observer.OnCompleted();

observers.Clear();
}
}

public class MessageUnknownException : Exception
{
internal MessageUnknownException()
{
}
}

public class Inspector : IObserver<Message>
{
private IDisposable unsubscriber;
private string instName;

public Inspector(string name)
{
this.instName = name;
}

public string Name
{
get
{
return this.instName;
}
}

public virtual void Subscribe(IObservable<Message> provider)
{
if (provider != null)
unsubscriber = provider.Subscribe(this);
}

public virtual void OnCompleted()
{
Console.WriteLine("The headquarters has completed transmitting data to {0}.", this.Name);
this.Unsubscribe();
}

public virtual void OnError(Exception e)
{
Console.WriteLine("{0}: Cannot get message from headquarters.", this.Name);
}

public virtual void OnNext(Message value)
{
Console.WriteLine("{1}: Message I got from headquarters: {0}", value.Text, this.Name);
}

public virtual void Unsubscribe()
{
unsubscriber.Dispose();
}
}

public class Program
{
public static void Main(string[] args)
{
Inspector inspector1 = new Inspector("Greg Lestrade");
Inspector inspector2 = new Inspector("Sherlock Holmes");

Headquarters headquarters = new Headquarters();

inspector1.Subscribe(headquarters);
inspector2.Subscribe(headquarters);

headquarters.SendMessage(new Message("Catch Moriarty!"));
headquarters.EndTransmission();

Console.ReadKey();
}
}


Related Topics



Leave a reply



Submit