A: Delegates enable scenarios that some other languages have addressed with
function pointers. However, unlike function pointers, delegates are object-oriented
and type-safe.
Not really. A delegate instance does not know or care about the classes of the
methods it encapsulates; all that matters is that those methods be compatible
with the delegate's type.
The problem is best illustrated with an example:
| using System;
class Department { public delegate void Fireable();
public static void FireEmployee(Fireable fireable) { fireable(); } }
class Military { public delegate void Fireable();
public static void FireMissile(Fireable fireable) { fireable(); } }
class Missile { public void Fire() { Console.WriteLine("missile fired"); } }
class Employee { public void Fire() { Console.WriteLine("employee fired"); } }
class Test { static Employee e1 = new Employee(); static Missile e2 = new Missile();
static void Main(string[] args) { Department.Fireable e = new Department.Fireable(e2.Fire); Department.FireEmployee(e); } } |
In this program, the programmer has made an error. The line
| Department.Fireable e = new Department.Fireable(e2.Fire);
|
really should be
| Department.Fireable e = new Department.Fireable(e1.Fire);
|
However the compiler does not detect this coding error. The program compiles
fine and you get this output when you run it:
Uh oh! The programmer intended to fire an employee, but he has launched
a missile instead!
A: Yes. You can get type safety by using interfaces instead of delegates.
| using System;
class Department { public interface Fireable { void Fire(); } public static void FireEmployee(Fireable fireable) { fireable.Fire(); } }
class Military { public interface Fireable { void Fire(); } public static void FireMissile(Fireable fireable) { fireable.Fire(); } }
class Missile : Military.Fireable { public void Fire() { Console.WriteLine("missile fired"); } }
class Employee : Department.Fireable { public void Fire() { Console.WriteLine("employee fired"); } }
class Test { static Employee e1 = new Employee(); static Missile e2 = new Missile();
static void Main(string[] args) { Department.Fireable e = e1; Department.FireEmployee(e); } } |
Try changing the line
| Department.Fireable e = e1;
|
to this:
| Department.Fireable e = e2;
|
When you try to compile the program the compiler tells you:
| test.cs(38,33): error CS0029: Cannot implicitly convert type 'Missile' to 'Department.Fireable'
|
The compiler has detected your coding error!
A: Type safety is about increasing the opportunities for the compiler to
detect your coding errors. If you use interfaces instead of delegates the
compiler will have more opportunities to
detect your coding errors.
A: Interfaces carry semantics, and when a programmer implements an interface,
he is typically well aware of that semantics. When you try to invoke a particular
method via an interface, you can be fairly certain that if you succeed, the
semantics of that method is what you expect. For that reason, using interfaces
is essentially doing a check for semantic correctness on some level.
Delegates, on the other hand, by only verifying the method signature, make the
programmer responsible for ensuring that the semantics of the method is compatible.
The semantics may cover not only the meaning of the arguments and return value
(some times even the order of the arguments if they are of the same type), the
ranges of the arguments, but also an invocation order when multiple methods are
concerned. Hence, in a sufficiently large program there is plenty of margin to
make an error when different programmers are not forced to comply with a uniform
semantics (as they would be if interfaces were used).
[credit: Mind Bridge]
A: Use of delegates results in shorter but less reliable code.
C# Best Practice
Prefer interfaces over delegates
|
[Back to Index]
|