C# Delegates, Events, Lambda

42
C#: Delegates, Events and Lambda Jussi Pohjolainen Tampere University of Applied Sciences

Transcript of C# Delegates, Events, Lambda

Page 1: C# Delegates, Events, Lambda

C#:  Delegates,  Events  and  Lambda  

Jussi  Pohjolainen  Tampere  University  of  Applied  Sciences  

Page 2: C# Delegates, Events, Lambda

About  Callbacks  

•  Callback  methods  can  be  implemented  in  C#  using  delegates,  events  and  lambda  

•  Callback  method?    – When  buGon  is  clicked,  a  method  is  called  (calls  back  a  method  you  have  implemented)  

•  Delegate  type  “points”  to  a  method  or  a  list  of  methods  –  Event  will  help  you  to  build  callback  mechanism  

•  Lambda  is  anonymous  method  and  provides  simplified  approach  working  with  delegates  

Page 3: C# Delegates, Events, Lambda

JavaScript:  Callback  function doSomething(integer, someFunction) { var i = 0, s = 0; for(i = 0; i<integer; i = i + 1) { s += integer; } // callback! someFunction(s); } function callBackFunction(result) { print('result is: ' + result); } function main() { doSomething(5000, callBackFunction); } main();

Page 4: C# Delegates, Events, Lambda

Java  7:  Anonymous  methods  and  callbacks  

// Kind of hard?

button.addActionListener( new ActionListener() {

public void actionPerformed(ActionEvent e) {

// do something

}

})

// Note: Java 8 will have lambda

Page 5: C# Delegates, Events, Lambda

Obj-­‐C:  Selectors  and  Callbacks  - (void) testSelectors { SEL variable; variable = @selector(animate); [self methodWithSelectorAsArgument: variable]; } - (void) methodWithSelectorAsArgument: (SEL) argument { [self performSelector:argument]; } - (void) animate { ... }

Page 6: C# Delegates, Events, Lambda

Delegate  

•  Delegate  type  holds  – Address  of  the  method  on  which  it  makes  calls  – Parameters  of  the  method  – Return  type  of  the  method  

•  Works  both  asynchronously  and  synchronously.  Simplifies  things,  no  need  for  Thread  object.  Let’s  see  this  later  

Page 7: C# Delegates, Events, Lambda

Example  // Following delegate type can point to whatever // method as long as it's returning int and it has two

// parameters.

public delegate int Something(int a, int b);

// This will generate a following class! Lot of methods

// also deriving from MulticastDelegate and Delegate (base class

// for MulticastDelegate)

sealed class Something : System.MulticastDelegate

{

public int Invoke(int x, int y);

public IAsyncResult BeginInvoke(int x, int y, AsyncCallback cb, object state);

public int EndInvoke(IAsyncResult result);

}

Page 8: C# Delegates, Events, Lambda

using System;

public delegate int Something(int a, int b);

class MyMath

{

public int Add(int a, int b)

{

return a + b;

}

}

class MyMain

{

public static void Main() {

MyMath m = new MyMath();

Something delegateObject = new Something(m.Add);

Console.WriteLine( delegateObject.Invoke(5,5) );

// Calls Invoke!

Console.WriteLine( delegateObject(5,5) );

}

}

Page 9: C# Delegates, Events, Lambda

using System;

public delegate int Something(int a, int b);

class MyMath

{

public static int Add(int a, int b)

{

return a + b;

}

}

class MyMain

{

public static void Main() {

Something delegateObject = new Something(MyMath.Add);

// Calls Invoke!

Console.WriteLine( delegateObject(5,5) );

}

}

Page 10: C# Delegates, Events, Lambda

class MyMain

{

public static void Main() {

Something delegateObject = new Something(MyMath.Add);

PrintInformation(delegateObject);

}

// All delegates inherite Delegate class

public static void PrintInformation(Delegate delObj)

{

// Remember that delegate may hold number of methods!

foreach(Delegate d in delObj.GetInvocationList())

{

// Result: Int32 Add(Int32, Int32)

Console.WriteLine(d.Method);

}

}

}

Page 11: C# Delegates, Events, Lambda

"REAL  WORLD"  EXAMPLE  

Page 12: C# Delegates, Events, Lambda

class Teacher {

// A new inner class is created here! The class inherits // System.MulticastDelegate

// This can point to whatever class that is void and one string // argument. This could be also outer-class. public delegate void TeacherHandler(string msg);

// Declare an attribute type of the new class. private TeacherHandler listOfHandlers;

// Helper method for assigning the attribute public void RegisterWithListener(TeacherHandler methodToCall) { listOfHandlers = methodToCall; }

public bool teacherIsBoring { get; set; }

public void teach() { // If teacher is not boring if(!teacherIsBoring) { // And there are someone listening if(listOfHandlers != null) { // Send message to the listener. listOfHandlers("C# is cool!"); } } }

}

Page 13: C# Delegates, Events, Lambda

using System; class MyMain {

public static void Main() { Teacher jussi = new Teacher(); // instantiate inner class object jussi.RegisterWithListener(new Teacher.TeacherHandler(OnTeachEvent)); jussi.teacherIsBoring = false;

jussi.teach(); }

// Since teacher is not boring and we are listening, // this method is called public static void OnTeachEvent(string m) { Console.WriteLine("Important message from teacher!"); Console.WriteLine(m); }

}

Page 14: C# Delegates, Events, Lambda

MULTICASTING  

Page 15: C# Delegates, Events, Lambda

// Helper method for assigning the attribute public void RegisterWithListener(TeacherHandler methodToCall) { if(listOfHandlers == null) { listOfHandlers = methodToCall; } else { Delegate.Combine(listOfHandlers, methodToCall); } }

Teacher jussi = new Teacher(); // instantiate inner class object jussi.RegisterWithListener(new Teacher.TeacherHandler(OnTeachEvent1)); jussi.RegisterWithListener(new Teacher.TeacherHandler(OnTeachEvent2)); jussi.teacherIsBoring = false;

jussi.teach();

Page 16: C# Delegates, Events, Lambda

// Helper method for assigning the attribute public void RegisterWithListener(TeacherHandler methodToCall) {

// And even more easier! listOfHandlers += methodToCall; }

Teacher jussi = new Teacher(); // instantiate inner class object jussi.RegisterWithListener(new Teacher.TeacherHandler(OnTeachEvent1)); jussi.RegisterWithListener(new Teacher.TeacherHandler(OnTeachEvent2)); jussi.teacherIsBoring = false;

jussi.teach();

Page 17: C# Delegates, Events, Lambda

REMOVING  TARGETS  

Page 18: C# Delegates, Events, Lambda

class MyMain {

public static void Main() { Teacher jussi = new Teacher(); // instantiate inner class object jussi.RegisterWithListener(new Teacher.TeacherHandler(OnTeachEvent1)); Teacher.TeacherHandler listener; jussi.RegisterWithListener(listener = new Teacher.TeacherHandler(OnTeachEvent2)); jussi.teacherIsBoring = false; jussi.teach();

jussi.UnRegisterWithListener(listener); jussi.teach();

}

..

// Helper method for assigning the attribute public void UnRegisterWithListener(TeacherHandler methodToCall) { listOfHandlers -= methodToCall; }

Page 19: C# Delegates, Events, Lambda

METHOD  GROUP  CONVERSION  

Page 20: C# Delegates, Events, Lambda

Method  Group  Conversion  

•  In  the  previous  example,  we  created  object  – Teacher.TeacherHandler  

•  You  don't  have  to  do  this!  •  Method  group  conversion!  – Direct  method  name  is  converted  to  a  delegate  object  

Page 21: C# Delegates, Events, Lambda

Method  Group  Conversion   public static void Main() { Teacher jussi = new Teacher(); jussi.RegisterWithListener(OnTeachEvent1); jussi.RegisterWithListener(OnTeachEvent2); jussi.teacherIsBoring = false; jussi.teach();

jussi.UnRegisterWithListener(OnTeachEvent2); jussi.teach();

}

Page 22: C# Delegates, Events, Lambda

EVENTS  

Page 23: C# Delegates, Events, Lambda

Simplify  Registering  

•  The  previous  example  had  methods  like  – public  void  RegisterWithListener(TeacherHandler  methodToCall)  

– public  void  UnRegisterWithListener(TeacherHandler  methodToCall)  

•  To  simplify  this,  we  can  use  events!  

Page 24: C# Delegates, Events, Lambda

class Teacher {

private int workHoursPerDay = 0;

public delegate void TeacherHandler(string msg);

// No register or unregister methods! // When using events, two hidden methods are generated: // add_AboutToOverload // remove_AboutToOverLoad public event TeacherHandler AboutToOverload; public event TeacherHandler MentallyDead;

public void teach() { workHoursPerDay++; if(workHoursPerDay >= 4 && workHoursPerDay < 6) { if(AboutToOverload != null) { AboutToOverload("TOO MUCH WORK FOR ME! Workhours = " + workHoursPerDay); } } else if(workHoursPerDay >= 6) { if(MentallyDead != null) { MentallyDead("CANNOT WORK ANYMORE, BITCH ABOUT THIS! Workhours = " + workHoursPerDay); } } }

}

Page 25: C# Delegates, Events, Lambda

class MyMain {

public static void Main() { Student pekka = new Student(); pekka.Name = "Pekka"; Supervisor jaska = new Supervisor(); jaska.Name = "Jaska";

Teacher jussi = new Teacher(); jussi.AboutToOverload += pekka.listen; jussi.AboutToOverload += jaska.listen; jussi.MentallyDead += jaska.listen;

jussi.teach(); jussi.teach(); jussi.teach(); jussi.teach(); jussi.teach(); jussi.teach(); jussi.teach(); jussi.teach();

}

}

Page 26: C# Delegates, Events, Lambda

class Student {

public string Name {get; set;} public void listen(string m) { Console.WriteLine(Name + " listening to teacher msg = " + m); }

} class Supervisor {

public string Name {get; set;}

public void listen(string m) { Console.WriteLine(Name + " listening to teacher msg = " + m); }

}

Page 27: C# Delegates, Events, Lambda

RECOMMEND  EVENT  PATTERN  

Page 28: C# Delegates, Events, Lambda

class Student {

public string Name {get; set;}

// Listener here get information: // 1) who is the sender? // 2) more information about the event

public void listen(object sender, TeacherEventArgs events) { Console.WriteLine(Name + " listening to teacher msg = " + events.msg); }

} class Supervisor {

public string Name {get; set;}

public void listen(object sender, TeacherEventArgs events) { Console.WriteLine(Name + " listening to teacher msg = " + events.msg); }

}

Page 29: C# Delegates, Events, Lambda

// Implement own custom event! public class TeacherEventArgs : EventArgs {

public readonly string msg; public TeacherEventArgs(string message) { msg = message; }

} // And use it class Teacher {

private int workHoursPerDay = 0;

public delegate void TeacherHandler(object sender, TeacherEventArgs e); … public void teach()

{ …

AboutToOverload(this, new TeacherEventArgs("TOO MUCH WORK …"));

… }

Page 30: C# Delegates, Events, Lambda

EVENTHANDLER<T>  DELEGATE  

Page 31: C# Delegates, Events, Lambda

public class TeacherEventArgs : EventArgs {

public readonly string msg; public TeacherEventArgs(string message) { msg = message; }

} class Teacher {

private int workHoursPerDay = 0;

/* public delegate void TeacherHandler(object sender, TeacherEventArgs e);

public event TeacherHandler AboutToOverload; public event TeacherHandler MentallyDead; */

// Now we can use the EventHandler class. Notice that there is no // need for the delegate anymore! public event EventHandler<TeacherEventArgs> AboutToOverload; public event EventHandler<TeacherEventArgs> MentallyDead;

Page 32: C# Delegates, Events, Lambda

class MyMain {

public static void Main() { Student pekka = new Student(); pekka.Name = "Pekka"; Supervisor jaska = new Supervisor(); jaska.Name = "Jaska";

Teacher jussi = new Teacher();

// Now we can use the EventHandler class! jussi.AboutToOverload += new EventHandler<TeacherEventArgs>(pekka.listen); jussi.AboutToOverload += jaska.listen; jussi.MentallyDead += jaska.listen;

Page 33: C# Delegates, Events, Lambda

Anonymous  Delegate  Methods  Teacher jussi = new Teacher();

jussi.AboutToOverload += delegate (object send, TeacherEventArgs events)

{

Console.WriteLine("anonymous delegate method 1!");

};

jussi.AboutToOverload += delegate

{

Console.WriteLine("anonymous delegate method 2!");

};

Page 34: C# Delegates, Events, Lambda

ABOUT  LAMBDA  

Page 35: C# Delegates, Events, Lambda

Lambda  Expressions  

•  Lambda  expression  is  an  anonymous  func\on  that  you  can  use  to  create  delegates  

•  Can  be  used  to  write  local  func\ons  that  can  be  passed  as  arguments  

•  Helpful  for  wri\ng  LINQ  query  expressions  (we  will  see  this  later,  maybe  J)    jussi.AboutToOverload +=

(object sender, TeacherEventArgs events) => Console.WriteLine("hello");

Page 36: C# Delegates, Events, Lambda

COLLECTIONS  

Page 37: C# Delegates, Events, Lambda

System.Collec\ons  •  All  Collec\on  classes  can  be  found  from  System.Collec\ons  

•  Classes  like  –  ArrayList  –  Hashtable    

•  key/value  –  Queue  

•  FIFO:  first-­‐in,  first-­‐out  –  SortedList  

•  key/value,  sorted  by  the  keys  –  Stack  

•  last-­‐in,  first-­‐out  

Page 38: C# Delegates, Events, Lambda

Example    

ArrayList list = new ArrayList();

list.Add("a");

list.Add("b");

list.add("c");

foreach(string s in list) { … }

Page 39: C# Delegates, Events, Lambda

Using  Generics  

ArrayList<string> list = new ArrayList<string>();

list.Add("a");

list.Add("b");

list.add("c");

list.add(2); // Fails

foreach(string s in list) { … }

Page 40: C# Delegates, Events, Lambda

Use  interfaces  

•  Use  this  –  IList<string> list = new ArrayList<string>();

•  Instead  of  this  – ArrayList<string> list = new Arraylist();

•  You  can  change  the  collec\on  class  later!  

Page 41: C# Delegates, Events, Lambda

ABOUT  THREADS  

Page 42: C# Delegates, Events, Lambda

Threading  

•  Ability  to  mul\task  •  Process  -­‐>  UI-­‐thread  -­‐>  other  threads  •  Use  System.Threading  •  Do  exercises  to  learn  about  threading!