120 likes | 159 Views
Programming in C# Delegates. CSE 494R (proposed course for 459 Programming in C#) Prof. Roger Crawfis. Delegates. Delegates are type definitions for function pointers . Once defined, they allow for type-safe (static) variables (instances) which point to functions (methods).
E N D
Programming in C#Delegates CSE 494R (proposed course for 459 Programming in C#) Prof. Roger Crawfis
Delegates • Delegates are type definitions for function pointers. Once defined, they allow for type-safe (static) variables (instances) which point to functions (methods). • They specify the signature of an individual method. This name does not matter. public delegate ComplexFunc1D(Complex x); Parameters: order and type Return Type Type Definition Name
Delegates vs. Interfaces • Delegates are similar to interfaces: they specify a contract between a caller and an implementer. • Interface: specifying an entire interface • Delegate: specifying a single function • Interface: created at compile-time • Delegate: created at run-time. Can be used to dynamically hook up callbacks between objects that weren’t originally designed to work together.
Examples • The following are type definitions: public delegate double Function( double x ); public delegate bool Predicate( double x ); public delegate void Action( double x ); • We can now assign variables these types: private Function log10 = System.Math.Log10; private Predicate isNegative = null; private Function operation = null; private Action print = new Action(Console.Writeline); • Reference types – default value of null.
Examples • Now we can use these variables. Call them just like you would a method: double y = log10(100.0); y += operation(-2); if( isNegative(y) ) … (new Action(Console.Writeline))(y);
Assigning Values • Any matching method can be assigned to a delegate instance delegate void Notifier (string sender); void SayHello( string name) { Console.WriteLine( “Hello from " + name); } greetings = new Notifier(SayHello); greetings(”Roger”); // SayGoodBye(“Roger") => “Hello from Roger“ • Note • If null, a delegate variable must not be called (otherwise it results in an exception). • Delegate variables are first class objects. They can be stored in a data structure, passed as a parameter, etc.
Creating a Delegate Value newDelegateType (instance.Method) • A delegate variable stores a method and its target. It does not store any parameters. new Notifier( myGreeting.SayHello ); • The target, instance, can be this (and can be omitted) new Notifier( SayHello ); • The method can be static. In this case the class name must be specified instead of the instance variable name.new Notifier( MyClass.StaticSayHello ); • The method can not be abstract (impossible), but it can be virtual.
Method Signatures • The method signature must match the signature of DelegateType • same number of parameters • same parameter types (including the return type) • same parameter attributes (ref, out) • With .NET 2.0 delegates are contra-variant in the parameters (any base type of the specified type) and covariant in the return type (any type derived from the specified return type).
Multicast Delegates • A delegate instance is actually a container of callback functions. It can hold a list of values. • The operators += and -= are defined to add and remove values. • The operator = clears the list and assigns it to the rhs. Notifier greetings; greetings = new Notifier(SayHello); greetings +=new Notifier(SayGoodBye); greetings("John"); // "Hello from John" // "Good bye from John" greetings -=new Notifier(SayHello); greetings("John"); // "Good bye from John“ • If the multicast delegate is a function, the value of the last call is returned. Avoid this! • If the multicast delegate has an out parameter, the parameter of the last call is returned. refParameters are passed through all methods. Do not assume any order to the calls.
Assignment of Delegates simplified forms: delegate type is inferred from the type of the left-hand side print = this.Foo; print = Foo; delegate double Function(double x); double Foo(double x) { return x * x; } overloading is resolved using the type of the left-hand side assigns Foo(string s) assigns Foo(double x) Printer print = Foo; Function square = Foo; delegate void Printer(string s); void Foo(string s) { Console.WriteLine(s); } Printer print; print = new Printer(this.Foo);
Generic Delegates delegate boolCheck<T>(T value); classPayment { public DateTime date; publicint amount; } internal classAccount { private IList<Payment> payments = new List<Payment >(); public voidAdd(Payment p) { payments.Add(p); } public intAmountPayed( Check<Payment> matches ) { int val = 0; foreach (Payment p in payments) if ( matches(p) ) val += p.amount; return val; } } A check method is passed, which checks for every Payment, whether it is eligible boolPaymentsAfter( Payment p ) { return DateTime.Compare( p.date, myDate ) >= 0; } ... myDate = new DateTime(2001, 11, 9); int val = account.AmountPayed( new Check<Payment>(PaymentsAfter) );
Programming in C#Delegates CSE 494R (proposed course for 459 Programming in C#) Prof. Roger Crawfis