C# Delegates, Events, Lambda
-
Upload
jussi-pohjolainen -
Category
Technology
-
view
1.610 -
download
7
Transcript of C# Delegates, Events, Lambda
C#: Delegates, Events and Lambda
Jussi Pohjolainen Tampere University of Applied Sciences
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
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();
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
Obj-‐C: Selectors and Callbacks - (void) testSelectors { SEL variable; variable = @selector(animate); [self methodWithSelectorAsArgument: variable]; } - (void) methodWithSelectorAsArgument: (SEL) argument { [self performSelector:argument]; } - (void) animate { ... }
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
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);
}
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) );
}
}
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) );
}
}
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);
}
}
}
"REAL WORLD" EXAMPLE
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!"); } } }
}
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); }
}
MULTICASTING
// 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();
// 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();
REMOVING TARGETS
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; }
METHOD GROUP CONVERSION
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
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();
}
EVENTS
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!
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); } } }
}
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();
}
}
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); }
}
RECOMMEND EVENT PATTERN
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); }
}
// 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 …"));
… }
EVENTHANDLER<T> DELEGATE
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;
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;
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!");
};
ABOUT 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");
COLLECTIONS
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
Example
ArrayList list = new ArrayList();
list.Add("a");
list.Add("b");
list.add("c");
foreach(string s in list) { … }
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) { … }
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!
ABOUT THREADS
Threading
• Ability to mul\task • Process -‐> UI-‐thread -‐> other threads • Use System.Threading • Do exercises to learn about threading!