Search

Categories

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Send mail to the author(s) E-mail

# Wednesday, 28 December 2011

Delegates – “they encapsulate a bit of behaviour”.. Initally from Jon Skeets Tekpub videos:

    public delegate void Int32Action(int value);

    public class Delegates
    {
        public void RandomRob(int value)
        {
            Console.WriteLine("Delegate implementation: {0}", value);  
        }

        //static means related to the type rather than any specific instance of the type
        public static void StaticRob(int value)
        {
            Console.WriteLine("Static method: {0}", value);  
        }
    }

and calling:

        [Test]
        public void SimpleDelegateFromMethod()
        {
            Delegates target = new Delegates();
            //C#1 syntax
            Int32Action action = new Int32Action(target.RandomRob);

            //same.. calling the delegate which has been setup to be target.RandomRob
            action.Invoke(5);
            action(6);
        }

        [Test]
        public void DelegateFromStaticMethod()
        {
            Int32Action action = new Int32Action(Delegates.StaticRob);
            action.Invoke(7);
        }

 

Events

Observer pattern.

Here we are using pub/sub without events:

    [TestFixture]
    public class FakeEventRaiserTest
    {
        private void ReportToConsole(string text)
        {
            Console.WriteLine("Called: {0}", text);
        }

        [Test]
        public void RaiseEvents()
        {
            //C#1
            //FakeEventHandler handler = new FakeEventHandler(ReportToConsole);
            //C#2 - implicit method group conversions
            FakeEventHandler handler = ReportToConsole;

            FakeEventRaiser raiser = new FakeEventRaiser();
            raiser.DoSomething("Not subscribed");

            raiser.AddHandler(handler);
            raiser.DoSomething("Subscribed");
            
            raiser.AddHandler(handler);
            raiser.DoSomething("Subscribed twice");

            raiser.RemoveHandler(handler);
            raiser.RemoveHandler(handler);
            raiser.DoSomething("Unsubscribed");
        }
    }

asdf

public class FakeEventRaiser
    {
        private FakeEventHandler currentHandler = null;

        public void AddHandler(FakeEventHandler handler)
        {
            currentHandler = currentHandler + handler;
        }

        public void RemoveHandler(FakeEventHandler handler)
        {
            currentHandler = currentHandler - handler;
        }

        public void DoSomething(string text)
        {
            FakeEventHandler tmp = currentHandler;
            if (tmp!=null)
                tmp.Invoke(text);
        }
    }

Longhand EventRaiser:

[TestFixture]
    public class LonghandEventRaiserTest
    {
        private void ReportToConsole(object sender, EventArgs e)
        {
            Console.WriteLine("ReportToConsole was called");
        }

        [Test]
        public void RaiseEvents()
        {
            //C#1
            //FakeEventHandler handler = new FakeEventHandler(ReportToConsole);
            //C#2 - implicit method group conversions
            ClickHandler handler = ReportToConsole;

            var raiser = new LonghandEventRaiser();
            raiser.OnClick("Not subscribed");

            raiser.Click += handler;
            raiser.OnClick("Subscribed");

            raiser.Click += handler;
            raiser.OnClick("Subscribed twice");

            raiser.Click -= handler;
            raiser.Click -= handler;
            raiser.OnClick("Unsubscribed");
        }
    }

asdf

namespace MasteringCSharp.Tests
{
    public delegate void ClickHandler(object sender, EventArgs e);

    public class LonghandEventRaiser
    {
        private ClickHandler currentHandler = null;

        private void AddHandler(ClickHandler handler)
        {
            currentHandler = currentHandler + handler;
        }

        private void RemoveHandler(ClickHandler handler)
        {
            currentHandler = currentHandler - handler;
        }

        public void OnClick(string text)
        {
            ClickHandler tmp = currentHandler;
            if (tmp!=null)
                tmp.Invoke(this, EventArgs.Empty);
        }

        public event ClickHandler Click
        {
            add { AddHandler(value);}
            remove {RemoveHandler(value);}
        }
    }
}

but can simplify..fairly simple implementation of the observer pattern:

    public delegate void ClickHandler(object sender, EventArgs e);

    public class LonghandEventRaiser
    {
        private ClickHandler currentHandler = null;

        public void OnClick(string text)
        {
            ClickHandler tmp = currentHandler;
            if (tmp!=null)
                tmp.Invoke(this, EventArgs.Empty);
        }

        public event ClickHandler Click
        {
            add { currentHandler += value; }
            remove {currentHandler -= value;}
        }
    }

but we can do better!

public void OnClick(string text)
        {
            //Click refers to the field which is auto genned
            ClickHandler tmp = Click;
            if (tmp!=null)
                tmp.Invoke(this, EventArgs.Empty);
        }

        //declared with a field like event
        public event ClickHandler Click;

 

 

Other Ways of thinking of Delegates and Events

“An event in C# is a way for a class to provide notifications to clients of that class when some interesting thing happens to an object”

http://www.akadia.com/services/dotnet_delegates_and_events.html

Calling a function directly:

    class Program
    {
        static void Main(string[] args)
        {
            MyClass mc = new MyClass();
            string result = mc.Process();
            Console.WriteLine(result);
        }
    }

    public class MyClass
    {
        public string Process()
        {
            return "In Process";
        }
    }

Basic Delegate

Sometimes we don’t want to call a function directly – we’d like to pass it to somebody else so they can call it.

    class Program
    {
        private delegate void LogDelegate(string s);

        static void Main(string[] args)
        {
            LogDelegate consoleLog = new LogDelegate(ConsoleLoggerFunction);
            consoleLog.Invoke("hello world");
            consoleLog("Another way");
        }

        static void ConsoleLoggerFunction(string s)
        {
            Console.WriteLine("Message is: {0}", s);
        }
    }

Calling Static Functions

    class Program
    {
        static void Main(string[] args)
        {
            Person p = new Person();
            Person.LogDelegate logger = new Person.LogDelegate(Logger);
            //implicit method group conversion
            //Person.LogDelegate logger = Logger;
            p.Process(logger);
        }

        private static void Logger(string message)
        {
            Console.WriteLine(message);
        }
    }

    public class Person
    {
        public delegate void LogDelegate(string message);

        public void Process(LogDelegate logDelegate)
        {
            if (logDelegate != null)
                logDelegate.Invoke("Doing stuff");
        }
    }

and then use a FakeLogger in tests:

        [Test]
        public void Process_WhenCalled_ShouldWriteToLogPassedIntoDelegate()
        {
            Person p = new Person();
            Person.LogDelegate logDelegate = new Person.LogDelegate(FakeLogger);

            p.Process(logDelegate);

        }

        private void FakeLogger(string message)
        {
            Console.WriteLine("FakeLogger: {0}", message);
        }

or could have simply used an interface:

******below is just for reference****** actually in the interest of keeping things simple, am going to go for more of an interface style in my TDD/Logging strategy as eventing can get complex quickly.

Calling Member Functions

hmm – could be better

internal class MyClass
    {
        //takes a single string parameter and no return type
        public delegate void LogHandler(string message);

        public void Process(LogHandler lh)
        {
            if (lh != null)
                lh("Process() begin");
            if (lh != null)
                lh("Process() end");
        }
    }

    // The FileLogger class merely encapsulates the file I/O
    public class FileLogger
    {
        FileStream fileStream;
        StreamWriter streamWriter;

        // Constructor
        public FileLogger(string filename)
        {
            fileStream = new FileStream(filename, FileMode.Create);
            streamWriter = new StreamWriter(fileStream);
        }

        // Member Function which is used in the Delegate
        public void Logger(string s)
        {
            streamWriter.WriteLine(s);
        }

        public void Close()
        {
            streamWriter.Close();
            fileStream.Close();
        }
    }

    public class TestApplication
    {
        static void Main(string[] args)
        {
            FileLogger fl = new FileLogger("process.log");
            MyClass mc = new MyClass();

            MyClass.LogHandler myLogger = new MyClass.LogHandler(fl.Logger);
            mc.Process(myLogger);
            fl.Close();
        }
    }

Events

  • Publishers
  • Subscribers

want a simple example of a logger using events - http://stackoverflow.com/questions/8663736/delegate-and-events-architecture-with-a-logger

public class Person
    {
        //takes a single string parameter and no return type
        public delegate void LogHandler(string message);

        // Define an Event based on the above Delegate
        public event LogHandler Log;

        //call the event using OnXXX where XXX is the name of the event
        public void Process()
        {
            OnLog("Process() begin");
            OnLog("Process() end");
        }

        protected void OnLog(string message)
        {
            if (Log != null)
                Log(message);
        }
    }

    public class FileLogger
    {
        FileStream fileStream;
        StreamWriter streamWriter;

        public FileLogger(string filename)
        {
            fileStream = new FileStream(filename, FileMode.Create);
            streamWriter = new StreamWriter(fileStream);
        }

        // Member Function which is used in the Delegate
        public void Logger(string s)
        {
            streamWriter.WriteLine(s);
        }

        public void Close()
        {
            streamWriter.Close();
            fileStream.Close();
        }
    }

    public class TestApplication
    {
        static void ConsoleLogger(string s)
        {
            Console.WriteLine(s);
        }

        static void Main(string[] args)
        {
            FileLogger fl = new FileLogger("process.log");
            Person person = new Person();

            // Subscribe the Functions ConsoleLogger and fl.ConsoleLogger
            person.Log += new Person.LogHandler(ConsoleLogger);
            person.Log += new Person.LogHandler(fl.Logger);

            person.Process();

            fl.Close();
        }
    }

and then:

    public delegate void FakeEventHandler(string reason);

    public class FakeEventRaiser
    {
        private FakeEventHandler currentHandler = null;

        public void AddHandler(FakeEventHandler handler)
        {
            currentHandler = currentHandler + handler;
        }

        public void RemoveHandler(FakeEventHandler handler)
        {
            currentHandler = currentHandler - handler;
        }

        public void DoSomething(string text)
        {
            FakeEventHandler tmp = currentHandler;
            if (tmp!=null)
                tmp.Invoke(text);
        }
    }
| | # 
# Monday, 27 July 2009
Thanks to:
http://davidhayden.com/blog/dave/archive/2006/05/28/2974.aspx

Anon methods, delegates, predicates.  Anon methods are simple shortcuts so don't have to declare a predicate method.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace TestAnonymousMethods
{
    public class Program
    {
        // using an anon method
        static void Mainx(string[] args)
        {
            int[] _integers = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };

            int[] evenIntegers = Array.FindAll(_integers,
                                        // this is the anonymous method below
                                       delegate(int integer)
                                       {
                                           return (integer % 2 == 0);
                                       }
                );

            foreach (int integer in _integers) 
                Console.WriteLine(integer);

            foreach (int integer in evenIntegers)
                Console.WriteLine(integer);
        }

        // not using anon method
        static void Mainy(string[] args)
        {
            int[] _integers = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };

            // passing in IsEven..a delegate which represents the IsEven method
            int[] evenIntegers = Array.FindAll(_integers, IsEven);

            foreach (int integer in _integers)
                Console.WriteLine(integer);

            foreach (int integer in evenIntegers)
                Console.WriteLine(integer);
        }

        static bool IsEven(int integer)
        {
            return (integer % 2 == 0);
        }


       
        // not using anon method and looking at predicate / delegate of Array.FindAll
        static void Main(string[] args)
        {
            int[] _integers = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
            // a predicate is expected
            // passing in IsEven..a delegate which represents the IsEven method
            int[] whatIsInBoth = Array.FindAll(_integers, IsDaveSequence);

            foreach (int integer in whatIsInBoth)
                Console.WriteLine(integer);

        }

        static bool IsDaveSequence(int integer)
        {
            bool returnState = false;
            if ((integer == 1) || (integer == 3) || (integer ==4))
                returnState = true;
            return returnState;
        }



    }
}

| | # 
# Thursday, 09 April 2009
Why use Events or publish / subscribe?

Any number of classes can be notified when an event is raised.

The subscribing classes do not need to know how the Metronome works, and the Metronome does not need to know what they are going to do in response to the event

The publisher and the subscribers are decoupled by the delegate. This is highly desirable as it makes for more flexible and robust code. The metronome can change how it detects time without breaking any of the subscribing classes. The subscribing classes can change how they respond to time changes without breaking the metronome. The two classes spin independently of one another, which makes for code that is easier to maintain.



Example1 - Metronome
Create a new console app, paste in the Main() code.  Then create 3 new classes (Alt P, C) - Metronome, Listener, ListenerB
A metronome ticks every 2 seconds, and two objects 'hear' it:

class Program
{
    static void Main()
    {
        // setup the metronome and make sure the EventHandler delegate is ready
        Metronome metronome = new Metronome();

        // wires up the metronome_Tick method to the EventHandler delegate
        Listener listener = new Listener(metronome);
        ListenerB listenerB = new ListenerB(metronome);
        metronome.Go();
    }
}

public class Metronome
{
    // a delegate
    // so every time Tick is called, the runtime calls another method
    // in this case Listener.metronome_Tick and ListenerB.metronome_Tick
    public event EventHandler Tick;

    // virtual so can override default behaviour in inherited classes easily
    protected virtual void OnTick(EventArgs e)
    {
        // null guard so if there are no listeners attached it wont throw an exception
        if (Tick != null)
            Tick(this, e);
    }

    public void Go()
    {
        while (true)
        {
            Thread.Sleep(2000);
            // because using EventHandler delegate, need to include the sending object and eventargs 
            // although we are not using them
            OnTick(EventArgs.Empty);
        }
    }
}


public class Listener
{
    public Listener(Metronome metronome)
    {
        metronome.Tick += new EventHandler(metronome_Tick);
    }
    
    private void metronome_Tick(object sender, EventArgs e)
    {
        Console.WriteLine("Heard it");
    }
}

public class ListenerB
{
    public ListenerB(Metronome metronome)
    {
        metronome.Tick += new EventHandler(metronome_Tick);
    }
    
    private void metronome_Tick(object sender, EventArgs e)
    {
        Console.WriteLine("ListenerB: Heard it");
    }
}    
Example2 - MetronomeArgs
We are passing the current time from the Metronome to the 2 listener objects
static void Main()
{
    // setup the metronome and make sure the EventHandler delegate is ready
    Metronome metronome = new Metronome();

    // wires up the metronome_Tick method to the EventHandler delegate
    Listener listener = new Listener(metronome);
    ListenerB listenerB = new ListenerB(metronome);
    metronome.Go();
}

public class Metronome
{
    // a delegate
    // so every time Tick is called, the runtime calls another method
    // in this case Listener.metronome_Tick
    // so objects subscribing to this delegate should look like (object sender, EventArgs e)
    public event EventHandler Tick;
   
    // virtual so can override default behaviour in inherited classes easily
    protected virtual void OnTick(TickEventArgs e)
    {
        // null guard so if there are no listeners attached it wont throw an exception
        if (Tick != null)
            Tick(this, e);
    }

    public void Go()
    {
        while (true)
        {
            Thread.Sleep(2000);
            DateTime now = DateTime.Now;
            TickEventArgs tickEventArgs = new TickEventArgs(now);
            OnTick(tickEventArgs);
        }
    }
}


// Good idea to inherit from EventArgs
// as can upcast EventArgs object in case you need to send it to an event that doesn't handle it???
// sole purpose of EventArgs class (which has no members) is to allow event arguments object to be passed to 
// event handlers
public class TickEventArgs : EventArgs
{
    public DateTime Time { get; private set; }

    public TickEventArgs(DateTime time)
    {
        this.Time = time;
    }
}

public class Listener
{
    public Listener(Metronome metronome)
    {
        metronome.Tick += new EventHandler(metronome_Tick);
    }

    private void metronome_Tick(object sender, EventArgs e)
    {
        // TickEventArgs is a superclass(?) of EventArgs... this is what we passed
        if (e is TickEventArgs)
        {
            // Downcasting e from EventArgs to TickEventArgs so can use its properties
            TickEventArgs tickEventArgs = e as TickEventArgs;
            
            Console.WriteLine("Heard it at time " + tickEventArgs.Time.ToString());
        }
    }
}

public class ListenerB
{
    public ListenerB(Metronome metronome)
    {
        metronome.Tick += new EventHandler(metronome_Tick);
    }
    
    private void metronome_Tick(object sender, EventArgs e)
    {
        Console.WriteLine("ListenerB: Heard it");
        
    }
}
References:
Big thanks on: http://stackoverflow.com/questions/724085/events-naming-convention-and-style
Metronome code is refactored from http://www.codeproject.com/KB/cs/simplesteventexample.aspx
Why use events: http://www.akadia.com/services/dotnet_delegates_and_events.html

| | #