evolution of c# delegates
DESCRIPTION
Evolution of C# delegates - overview of delegates in C#, from basic delegates in C# 1.0 to lambda expressions on C# 4.0TRANSCRIPT
![Page 2: Evolution of C# delegates](https://reader036.vdocuments.net/reader036/viewer/2022081420/554ebbd3b4c905de468b478e/html5/thumbnails/2.jpg)
Agenda
• Basic delegates• Delegate types, delegate instances
• Combining multiple delegates• Method group conversions• Covariance and contravariance• Inline delegate actions• Captured variables (closures)• Lambda expressions
![Page 3: Evolution of C# delegates](https://reader036.vdocuments.net/reader036/viewer/2022081420/554ebbd3b4c905de468b478e/html5/thumbnails/3.jpg)
• Provide a level of indirection• Sort of "sigle method interface"• Delegates inhert from
System.Delegate
• To create and use delegates:• The delegate type needs to be declared• The code to be executed must be contained
in a method• A delegate instance must be created• The delegate instance must be invoked
What is a delegate?
![Page 4: Evolution of C# delegates](https://reader036.vdocuments.net/reader036/viewer/2022081420/554ebbd3b4c905de468b478e/html5/thumbnails/4.jpg)
delegate void StringProcessor(string input);
Declaring delegate types
keyword returntype
delegate type name arguments
![Page 5: Evolution of C# delegates](https://reader036.vdocuments.net/reader036/viewer/2022081420/554ebbd3b4c905de468b478e/html5/thumbnails/5.jpg)
class MyClass{ public void SomeMethod(string input) public static void SomeMethodStatic(string input)}
StringProcessor p1 = new StringProcessor(myClassInstance.SomeMethod);
StringProcessor p2 = new StringProcessor(MyClass.SomeMethod);
Creating delegate instances
delegate type
delegate instance variable
action to invoke on MyClass instance
static action to invoke on MyClass
![Page 6: Evolution of C# delegates](https://reader036.vdocuments.net/reader036/viewer/2022081420/554ebbd3b4c905de468b478e/html5/thumbnails/6.jpg)
StringProcessor p1 = new StringProcessor(myClassInstance.SomeMethod);
p1.Invoke("Some string");
// ...or shorter version p1("Some string");
Invoking delegates
p1("Some string");
p1.Invoke("Some string")
SomeMethod("Some string")
• Delegates can be treated like any other type• They have methods, multiple instance can be created...
![Page 7: Evolution of C# delegates](https://reader036.vdocuments.net/reader036/viewer/2022081420/554ebbd3b4c905de468b478e/html5/thumbnails/7.jpg)
delegate void StringProcessor(string input);class Person{ private string name; public Person(string name) { this.name = name; } public void SayTheMessage(string message) { Console.WriteLine("{0} says: {1}", name, message); } public static void SayTheMessageStatic(string message) { Console.WriteLine(message); } }
static void Main(string[] args){ Person john = new Person("John"); Person tom = new Person("Tom"); StringProcessor johnsVoice = new StringProcessor(john.SayTheMessage); StringProcessor tomsVoice = new StringProcessor(tom.SayTheMessage); StringProcessor someonesVoice = new StringProcessor(Person.SayTheMessageStatic);
johnsVoice("Hello!"); tomsVoice.Invoke("Hello!"); someonesVoice("Just saying something...");}
Example
// Result: "John says: Hello!""Tom says: Hello!""Just saying something..."
![Page 8: Evolution of C# delegates](https://reader036.vdocuments.net/reader036/viewer/2022081420/554ebbd3b4c905de468b478e/html5/thumbnails/8.jpg)
• All delegates inherit methods from System.Delegate:• Delegate.Combine()• Delegate.Remove()
• Every delegate has an invocation list - a list of actions to invoke
• "+", "+=", "-", "-="• When delegate is invoked, all
actions in the invocation list are invoked in the order they were added
Combining the delegates
![Page 9: Evolution of C# delegates](https://reader036.vdocuments.net/reader036/viewer/2022081420/554ebbd3b4c905de468b478e/html5/thumbnails/9.jpg)
Person john = new Person("John");Person tom = new Person("Tom");Person mike = new Person("Mike");
StringProcessor johnsVoice = new StringProcessor(john.SayTheMessage);StringProcessor tomsVoice = new StringProcessor(tom.SayTheMessage);StringProcessor mikesVoice = new StringProcessor(mike.SayTheMessage);
StringProcessor twoCombined = johnsVoice + tomsVoice;StringProcessor allCombined = twoCombined + mikesVoice;allCombined += new StringProcessor(john.SayTheMessage);
allCombined("What's up!");
// Result: "John says: What's up!""Tom says: What's up!""Mike says: What's up!""John says: What's up!"
Example of combining delegates
![Page 10: Evolution of C# delegates](https://reader036.vdocuments.net/reader036/viewer/2022081420/554ebbd3b4c905de468b478e/html5/thumbnails/10.jpg)
//Delegate typedelegate void KeyPressEventHandler(object sender, KeyPressEventArgs e);
//Target actionvoid LogKeyEvent(object sender, KeyPressEventArgs e){ /* do something */ }
void LogKeyEvent(int x){ /* do something */ }
button.KeyPress += new KeyPressEventHandler(LogKeyEvent);
button.KeyPress += LogKeyEvent;
Method group converions
Method group is converted to compatible delegate type
![Page 11: Evolution of C# delegates](https://reader036.vdocuments.net/reader036/viewer/2022081420/554ebbd3b4c905de468b478e/html5/thumbnails/11.jpg)
Click -----> void EventHandler(object sender, EventArgs e)KeyPress -----> void KeyPressEventHandler(object sender, KeyPressEventArgs e)MouseClick ---> void MouseClickEventHandler(object sender, MouseEventArgs e)
Button button = new Button();button.Text = "Click me";button.Click += LogPlainEvent;button.KeyPress += LogPlainEvent;button.MouseClick += LogPlainEvent;
Form form = new Form();form.Controls.Add(button);Application.Run(form);
static void LogEvent(object sender, EventArgs e){ Console.WriteLine("An event occurred");}
Contravariance of delegates
Same action for 3 different delegates!
![Page 12: Evolution of C# delegates](https://reader036.vdocuments.net/reader036/viewer/2022081420/554ebbd3b4c905de468b478e/html5/thumbnails/12.jpg)
delegate Stream MyDelegate();
static MemoryStream GenerateSampleData(){ byte[] buffer = new byte[16]; return new MemoryStream(buffer);}
MyDelegate d = GenerateSampleData();Stream stream = d();MemoryStream stream = d();
Covariance of delegates
Stream
MemoryStream
![Page 13: Evolution of C# delegates](https://reader036.vdocuments.net/reader036/viewer/2022081420/554ebbd3b4c905de468b478e/html5/thumbnails/13.jpg)
Built-in delegate types in .NET
delegate void Action<T>(T arg);delegate void Action<T1, T2>(T1 arg1, T2 arg2);...
delegate TResult Func<T, TResult>(T arg);delegate TResult Func<T1, T2, TResult>(T1 arg1, T2 arg2);...
delegate bool Predicate<T>(T arg);...
![Page 14: Evolution of C# delegates](https://reader036.vdocuments.net/reader036/viewer/2022081420/554ebbd3b4c905de468b478e/html5/thumbnails/14.jpg)
• You don't need action method to exist - you can create it inline
Inline delegate actions
Action<int> printRoot = delegate(int number){ Console.WriteLine(Math.Sqrt(number));};
printRoot(9);
Func<string, int> getLength = delegate(string input){ return input.Length;};
int length = getLength("Some string");
Invoke it like other delegates
![Page 15: Evolution of C# delegates](https://reader036.vdocuments.net/reader036/viewer/2022081420/554ebbd3b4c905de468b478e/html5/thumbnails/15.jpg)
button.Click += delegate(object sender, EventArgs e) { ... };
Button button = new Button();button.Text = "Click me";button.Click += delegate { Console.WriteLine("Click"); };button.KeyPress += delegate { Console.WriteLine("KeyPress"); };button.MouseClick += delegate { Console.WriteLine("MouseClick"); };
Ingnoring inline delegate arguments
• When you won't use delegate arguments you can loose them in definition
![Page 16: Evolution of C# delegates](https://reader036.vdocuments.net/reader036/viewer/2022081420/554ebbd3b4c905de468b478e/html5/thumbnails/16.jpg)
• Beware of the compiler limitations:
Ingnoring inline delegate arguments
// Thread class has several different constructorspublic Thread(ThreadStart start)public Thread(ParameterizedThreadStart start)
// There are 2 types of delegates involvedpublic delegate void ThreadStart()public delegate void ParameterizedThreadStart(object obj)
new Thread(delegate() { Console.WriteLine("Something..."); } );new Thread(delegate(object o) { Console.WriteLine("Something..."); } );new Thread(delegate { Console.WriteLine("Something..."); } );
![Page 17: Evolution of C# delegates](https://reader036.vdocuments.net/reader036/viewer/2022081420/554ebbd3b4c905de468b478e/html5/thumbnails/17.jpg)
Captured variables (closures)
• Captured variables are outer variables used (captured) in the scope of anonymous methodvoid EnclosingMethod(){ string outerVariable = "Default string";
Action<int> a = delegate() { string localVariable = outerVariable; };
a();}
![Page 18: Evolution of C# delegates](https://reader036.vdocuments.net/reader036/viewer/2022081420/554ebbd3b4c905de468b478e/html5/thumbnails/18.jpg)
delegate void MyDelegate();
string captured = "before x is created";MyDelegate x = delegate{ Console.WriteLine(captured); captured = "changed by x";};captured = "before x is invoked";x();Console.WriteLine(captured);captured = "before second invocation";x();
// Result:"before x is invoked""changed by x""before second invocation"
Captured variables
The captured variable is the same one that the outer code uses!!!
![Page 19: Evolution of C# delegates](https://reader036.vdocuments.net/reader036/viewer/2022081420/554ebbd3b4c905de468b478e/html5/thumbnails/19.jpg)
• A captured variable lives for at least as long as any delegate instance referring to it
Lifetime of captured variables
public MethodInvoker CreateDelegateInstance(){ int counter = 5; MethodInvoker increment = delegate { Console.WriteLine(counter); counter++; };
increment(); return counter;}...
MethodInvoker x = CreateDelegateInstance();x();x();
![Page 20: Evolution of C# delegates](https://reader036.vdocuments.net/reader036/viewer/2022081420/554ebbd3b4c905de468b478e/html5/thumbnails/20.jpg)
MethodInvoker[] invokers = new MethodInvoker[2];
int outsideVariable = 0;for (int i=0; i<2; i++){ int insideVariable = 0; invokers[i] = delegate { Console.WriteLine ("({0},{1})", outsideVariable, insideVariable); outsideVariable++; insideVariable++; };}MethodInvoker first = invokers[0];MethodInvoker second = invokers[1];
first();first();first();second();second();
Things can get tricky very fast
// Result:(0,0)(1,1)(2,2)(3,0)(4,1)
![Page 21: Evolution of C# delegates](https://reader036.vdocuments.net/reader036/viewer/2022081420/554ebbd3b4c905de468b478e/html5/thumbnails/21.jpg)
• They are evolution of anonymous methods
• More readable and compact than other delegate forms
• Many shortcuts and "syntatic sugar" tricks allow most compat form of code
• Brings new operator "=>" (spelled as "goes to")
Lambda expressions
![Page 22: Evolution of C# delegates](https://reader036.vdocuments.net/reader036/viewer/2022081420/554ebbd3b4c905de468b478e/html5/thumbnails/22.jpg)
delegate TResult Func<T, TResult>(T input);
Func<string, int> returnLength;returnLength = delegate (string text) { return text.Length; };
returnLength = (string text) => { return text.Length; };
Simple lambda expression
input arguments statements
(list of input arguments) => { statements }
![Page 23: Evolution of C# delegates](https://reader036.vdocuments.net/reader036/viewer/2022081420/554ebbd3b4c905de468b478e/html5/thumbnails/23.jpg)
returnLength = (string text) => { return text.Length; }
returnLength = (string text) => text.Length
returnLength = (text) => text.Length
returnLength = text => text.Length
Shortening the lambdas
If the statement is single expression, you can loose the braces, return statement and semicolon
Compiler can guess type of input arguments,so you can loose it
If there is single input argument, you can loose the parentheses
![Page 24: Evolution of C# delegates](https://reader036.vdocuments.net/reader036/viewer/2022081420/554ebbd3b4c905de468b478e/html5/thumbnails/24.jpg)
Let's recap
Func<string, int> returnLength = new Func<string, int>(GetLength);returnLength(text);
Func<string, int> returnLength = GetLength;returnLength(text);
returnLength = delegate (string text) { return text.Length; };
returnLength = (string text) => { return text.Length; };
returnLength = text => text.Length;
![Page 25: Evolution of C# delegates](https://reader036.vdocuments.net/reader036/viewer/2022081420/554ebbd3b4c905de468b478e/html5/thumbnails/25.jpg)
public static IEnumerable<T> Where<T>(this IEnumerable<T> source, Func<T, bool> predicate){ if (source == null || predicate == null) { throw new ArgumentNullExcpetion(); }
foreach (T item in source) { if (predicate(item)) { yield return item; } } }
// Usage:var items = new List<string> { "John", "Tom", "Mike" };var filteredItems = items.Where(i => i.StartsWith("J"));
Real-life lamba example - Where
![Page 26: Evolution of C# delegates](https://reader036.vdocuments.net/reader036/viewer/2022081420/554ebbd3b4c905de468b478e/html5/thumbnails/26.jpg)
Real-life lambdas in action
![Page 27: Evolution of C# delegates](https://reader036.vdocuments.net/reader036/viewer/2022081420/554ebbd3b4c905de468b478e/html5/thumbnails/27.jpg)
Q & A?
![Page 28: Evolution of C# delegates](https://reader036.vdocuments.net/reader036/viewer/2022081420/554ebbd3b4c905de468b478e/html5/thumbnails/28.jpg)
Thank you!