title: Why Observer pattern is much more complicated in C# than in Ruby?
body: <p>I've read in <a href="http://designpatternsinruby.com/" rel="nofollow noreferrer">"Design Patterns in Ruby" by Russ Olsen</a> 
  how Observer pattern can be implemented in Ruby. I've noticed that Ruby implementation 
  of this pattern is much simpler than C# implementation, 
  e.g. implementation shown in <a href="http://oreilly.com/catalog/9780596527563" rel="nofollow noreferrer">"Programming .NET 3.5" by Jesse Liberty and 
  Alex Horovitz</a>.</p>
  
  <p>So I've rewritten "Programming .NET 3.5" Observer pattern example
  (page 251 of pdf edition) using "Design Patterns in Ruby" 
  algorithm, source code for both implementations can be downloaded 
  from the mentioned websites.</p>
  
  <p>Below is the rewritten example, tell me what do you think? <br/>
  Do we really need to use events and delegates to use the Observer pattern 
  in C#?
  <br /><br>
  <br />  </p>
  
  <p><strong>Update</strong>
  After reading comments I would like to ask this question: <br />
  Is there any other reason to use delegates and events besides that it makes code shorter?
  And I don't talk about GUI programming.</p>
  
  <p><strong>Update2</strong>
  I finally got it, delegate is simply a function pointer and event is safer version of delegate which only allows two operations += and -=.</p>
  
  <p>My rewrite of "Programming .NET 3.5" example:</p>
  
  <pre><code>using System;
  using System.Collections.Generic;
  
  namespace MyObserverPattern
  {
      class Program
      {
          static void Main()
          {
              DateTime now = DateTime.Now;
  
              // Create new flights with a departure time and add from and to destinations
              CarrierSchedule jetBlue = new CarrierSchedule("JetBlue", now);
              jetBlue.Attach(new AirTrafficControl("Boston"));
              jetBlue.Attach(new AirTrafficControl("Seattle"));
  
              // ATCs will be notified of delays in departure time
              jetBlue.DepartureDateTime =
                  now.AddHours(1.25); // weather delay
  
              jetBlue.DepartureDateTime =
                  now.AddHours(1.75); // weather got worse
  
              jetBlue.DepartureDateTime =
                  now.AddHours(0.5);  // security delay
  
              jetBlue.DepartureDateTime =
                  now.AddHours(0.75); // Seattle puts a ground stop in place
  
              // Wait for user
              //Console.Read();
          }
      }
  
  
      // Subject: This is the thing being watched by Air Traffic Control centers
      abstract class AirlineSchedule
      {
  
          // properties 
          public string Name { get; set; }
          public string DeparturnAirport { get; set; }
          public string ArrivalAirport { get; set; }
          private DateTime departureDateTime;
  
          private List&lt;IATC&gt; observers = new List&lt;IATC&gt;();
  
  
          public AirlineSchedule(string airline, 
                                 string outAirport, 
                                 string inAirport, 
                                 DateTime leaves )
          {
              this.Name = airline;
              this.DeparturnAirport = outAirport;
              this.ArrivalAirport = inAirport;
              this.DepartureDateTime = leaves;
          }
  
  
          // Here is where we actually attach our observers (ATCs)
          public void Attach(IATC atc)
          {
              observers.Add(atc);
          }
  
          public void Detach(IATC atc)
          {
              observers.Remove(atc);
          }
  
  
          public void OnChange(AirlineSchedule asched)
          {
              if (observers.Count != 0)
              {
                  foreach (IATC o in observers)
                      o.Update(asched);
              }
          }
  
          public DateTime DepartureDateTime
          {
              get { return departureDateTime; }
  
              set
              {
                  departureDateTime = value;
                  OnChange(this);
                  Console.WriteLine("");
              }
          }
      }// class AirlineSchedule
  
  
      // A Concrete Subject
      class CarrierSchedule : AirlineSchedule
      {
          // Jesse and Alex only really ever need to fly to one place...
          public CarrierSchedule(string name, DateTime departing) :
              base(name, "Boston", "Seattle", departing)
          {
          }
      }
  
  
      // An Observer
      interface IATC
      {
          void Update(AirlineSchedule sender);
      }
  
  
      // The Concrete Observer
      class AirTrafficControl : IATC
      {
          public string Name { get; set; }
  
          public AirTrafficControl(string name)
          {
              this.Name = name;
          }
  
          public void Update(AirlineSchedule sender)
          {
              Console.WriteLine(
                  "{0} Air Traffic Control Notified:\n {1}'s flight 497 from {2} " +
                  "to {3} new deprture time: {4:hh:mmtt}",
                  Name,
                  sender.Name,
                  sender.DeparturnAirport,
                  sender.ArrivalAirport,
                  sender.DepartureDateTime );
              Console.WriteLine("---------");
          }
      }
  
  }
  </code></pre>
  
  <p>Here is mentioned Ruby code:</p>
  
  <pre><code>module Subject
    def initialize
      @observers=[]
    end
    def add_observer(observer)
      @observers &lt;&lt; observer
    end
    def delete_observer(observer)
      @observers.delete(observer)
    end
    def notify_observers
      @observers.each do |observer|
        observer.update(self)
      end
    end
  end
  
  
  class Employee
    include Subject
  
    attr_reader :name, :address
    attr_reader :salary
  
    def initialize( name, title, salary)
      super()
      @name = name
      @title = title
      @salary = salary
    end
    def salary=(new_salary)
      @salary = new_salary
      notify_observers
    end
  end
  
  class TaxMan
    def update( changed_employee )
      puts("Send #{changed_employee.name} a new tax bill!")
    end
  end
  
  fred = Employee.new('Fred', 'Crane Operator', 30000.0)
  tax_man = TaxMan.new
  fred.add_observer(tax_man)
  </code></pre>
  
  <p>Here is "Programming .NET 3.5" example that I rewrote:</p>
  
  <pre><code>using System;
  
  namespace Observer
  {
      class Program
      {
  
          static void Main()
          {
              DateTime now = DateTime.Now;
              // Create new flights with a departure time and add from and to destinations
              CarrierSchedule jetBlue = new CarrierSchedule("JetBlue", now);
              jetBlue.Attach(new AirTrafficControl("Boston"));
              jetBlue.Attach(new AirTrafficControl("Seattle"));
  
              // ATCs will be notified of delays in departure time
              jetBlue.DepartureDateTime = 
                  now.AddHours(1.25); // weather delay
  
              jetBlue.DepartureDateTime = 
                  now.AddHours(1.75); // weather got worse
  
              jetBlue.DepartureDateTime = 
                  now.AddHours(0.5);  // security delay
  
              jetBlue.DepartureDateTime = 
                  now.AddHours(0.75); // Seattle puts a ground stop in place
  
              // Wait for user
              Console.Read();
          }
      }
  
      // Generic delegate type for hooking up flight schedule requests
      public delegate void ChangeEventHandler&lt;T,U&gt;
          (T sender, U eventArgs);
  
      // Customize event arguments to fit the activity
      public class ChangeEventArgs : EventArgs 
      {
          public ChangeEventArgs(string name, string outAirport, string inAirport, DateTime leaves) 
          {
              this.Airline = name;
              this.DeparturnAirport = outAirport;
              this.ArrivalAirport = inAirport;
              this.DepartureDateTime = leaves;
          }
  
          // Our Properties
          public string Airline               { get; set; }
          public string DeparturnAirport      { get; set; }
          public string ArrivalAirport        { get; set; }
          public DateTime DepartureDateTime   { get; set; }
  
      }  
  
      // Subject: This is the thing being watched by Air Traffic Control centers
      abstract class AirlineSchedule
      {
  
          // properties 
          public string Name                  { get; set; }
          public string DeparturnAirport      { get; set; }
          public string ArrivalAirport        { get; set; }
          private DateTime departureDateTime;
  
          public AirlineSchedule(string airline, string outAirport, string inAirport, DateTime leaves)
          {
              this.Name = airline;
              this.DeparturnAirport = outAirport;
              this.ArrivalAirport = inAirport;
              this.DepartureDateTime = leaves;
          }
  
          // Event
          public event ChangeEventHandler&lt;AirlineSchedule, ChangeEventArgs&gt; Change;
  
          // Invoke the Change event
          public virtual void OnChange(ChangeEventArgs e) 
          {
              if (Change != null)
              {
                  Change(this, e);
              }
          }
  
          // Here is where we actually attach our observers (ATCs)
          public void Attach(AirTrafficControl airTrafficControl)
          {
              Change += 
                  new ChangeEventHandler&lt;AirlineSchedule, ChangeEventArgs&gt;
                      (airTrafficControl.Update);
          }
  
          public void Detach(AirTrafficControl airTrafficControl)
          {
              Change -= new ChangeEventHandler&lt;AirlineSchedule, ChangeEventArgs&gt;
                  (airTrafficControl.Update);
          }
  
  
          public DateTime DepartureDateTime
          {
              get { return departureDateTime; }
              set
              {
                  departureDateTime = value;
                  OnChange(new ChangeEventArgs(
                      this.Name, 
                      this.DeparturnAirport,
                      this.ArrivalAirport,
                      this.departureDateTime));
                  Console.WriteLine("");
              }
          }
  
  
      }
  
      // A Concrete Subject
      class CarrierSchedule : AirlineSchedule
      {
          // Jesse and Alex only really ever need to fly to one place...
          public CarrierSchedule(string name, DateTime departing): 
              base(name,"Boston", "Seattle", departing)
          {
          }
      }
  
      // An Observer
      interface IATC
      {
          void Update(AirlineSchedule sender, ChangeEventArgs e);
      }
  
      // The Concrete Observer
      class AirTrafficControl : IATC
      {
          public string Name { get; set; }
  
          // Constructor
          public AirTrafficControl(string name)
          {
               this.Name = name;
          }
  
          public void Update(AirlineSchedule sender, ChangeEventArgs e)
          {
  
              Console.WriteLine(
                  "{0} Air Traffic Control Notified:\n {1}'s flight 497 from {2} " +
                  "to {3} new deprture time: {4:hh:mmtt}", 
                  Name, 
                  e.Airline, 
                  e.DeparturnAirport, 
                  e.ArrivalAirport, 
                  e.DepartureDateTime);
              Console.WriteLine("---------");
          }
          public CarrierSchedule CarrierSchedule { get; set; }
      }
  }
  </code></pre>