Evolution of C# delegates

  • 342 views
Uploaded on

Evolution of C# delegates - overview of delegates in C#, from basic delegates in C# 1.0 to lambda expressions on C# 4.0

Evolution of C# delegates - overview of delegates in C#, from basic delegates in C# 1.0 to lambda expressions on C# 4.0

  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Be the first to comment
    Be the first to like this
No Downloads

Views

Total Views
342
On Slideshare
0
From Embeds
0
Number of Embeds
0

Actions

Shares
Downloads
28
Comments
0
Likes
0

Embeds 0

No embeds

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
    No notes for slide
  • - Delegate instanca će onemogućiti da garbage collector očisti njen target dok kod je ona živa. Ovo može stvoriti neželjeni memory leak jer će long-lived objekt (u našem slučaju instanca delegata) držati na životu short-lived objekt (u našem slučaju target)

Transcript

  • 1. Evolution of C# delegates Marko Barić Senior software engineer @ Siemens CVC marko.baric@siemens.com
  • 2. Agenda • Basic delegates • • • • • • • Delegate types, delegate instances Combining multiple delegates Method group conversions Covariance and contravariance Inline delegate actions Captured variables (closures) Lambda expressions
  • 3. What is a delegate? • • • • 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
  • 4. Declaring delegate types delegate void StringProcessor(string input); keyword return type delegate type name arguments
  • 5. Creating delegate instances class MyClass { public void SomeMethod(string input) public static void SomeMethodStatic(string input) } StringProcessor p1 = new StringProcessor(myClassInstance.SomeMethod); delegate instance variable delegate type action to invoke on MyClass instance StringProcessor p2 = new StringProcessor(MyClass.SomeMethod); static action to invoke on MyClass
  • 6. Invoking delegates StringProcessor p1 = new StringProcessor(myClassInstance.SomeMethod); p1.Invoke("Some string"); // ...or shorter version p1("Some string"); 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...
  • 7. Example 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"); // Result: "John says: Hello!" "Tom says: Hello!" "Just saying something..." 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..."); }
  • 8. Combining the delegates • 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
  • 9. Example of combining delegates 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!"
  • 10. Method group converions //Delegate type delegate void KeyPressEventHandler(object sender, KeyPressEventArgs e); //Target action void LogKeyEvent(object sender, KeyPressEventArgs e) { /* do something */ } void LogKeyEvent(int x) { /* do something */ } button.KeyPress += new KeyPressEventHandler(LogKeyEvent); button.KeyPress += LogKeyEvent; Method group is converted to compatible delegate type
  • 11. Contravariance of delegates 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; Same action for 3 different delegates! Form form = new Form(); form.Controls.Add(button); Application.Run(form); static void LogEvent(object sender, EventArgs e) { Console.WriteLine("An event occurred"); }
  • 12. Covariance of delegates delegate Stream MyDelegate(); Stream static MemoryStream GenerateSampleData() { byte[] buffer = new byte[16]; return new MemoryStream(buffer); } MyDelegate d = GenerateSampleData(); Stream stream = d(); MemoryStream stream = d(); MemoryStream
  • 13. 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); ...
  • 14. Inline delegate actions • You don't need action method to exist you can create it inline Action<int> printRoot = delegate(int number) { Console.WriteLine(Math.Sqrt(number)); }; printRoot(9); Invoke it like other delegates Func<string, int> getLength = delegate(string input) { return input.Length; }; int length = getLength("Some string");
  • 15. Ingnoring inline delegate arguments • When you won't use delegate arguments you can loose them in definition 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"); };
  • 16. Ingnoring inline delegate arguments • Beware of the compiler limitations: // Thread class has several different constructors public Thread(ThreadStart start) public Thread(ParameterizedThreadStart start) // There are 2 types of delegates involved public 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..."); } );
  • 17. Captured variables (closures) • Captured variables are outer variables used (captured) in the scope of anonymous method void EnclosingMethod() { string outerVariable = "Default string"; Action<int> a = delegate() { string localVariable = outerVariable; }; a(); }
  • 18. Captured variables 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" The captured variable is the same one that the outer code uses!!!
  • 19. Lifetime of captured variables • A captured variable lives for at least as long as any delegate instance referring to it MethodInvoker CreateDelegateInstance() public { int counter = 5; MethodInvoker increment = delegate { Console.WriteLine(counter); counter++; }; increment(); return counter; } ... MethodInvoker x = CreateDelegateInstance(); x(); x();
  • 20. Things can get tricky very fast 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]; // Result: MethodInvoker second = invokers[1]; (0,0) first(); first(); first(); second(); second(); (1,1) (2,2) (3,0) (4,1)
  • 21. Lambda expressions • 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")
  • 22. Simple lambda expression delegate TResult Func<T, TResult>(T input); Func<string, int> returnLength; returnLength = delegate (string text) { return text.Length; }; (list of input arguments) => { statements } returnLength = (string text) => { return text.Length; }; input arguments statements
  • 23. Shortening the lambdas returnLength = (string text) => { return text.Length; } If the statement is single expression, you can loose the braces, return statement and semicolon returnLength = (string text) => text.Length Compiler can guess type of input arguments, so you can loose it returnLength = (text) => text.Length If there is single input argument, you can loose the parentheses returnLength = text => text.Length
  • 24. 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;
  • 25. Real-life lamba example - Where 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"));
  • 26. Real-life lambdas in action
  • 27. Q & A?
  • 28. Thank you!