1. Delegate compatibility
1) type compatibility
Delegate types are all incompatible with each other, even if their signatures are the same
Delegate void D1 (); Delegate void D2 ();...
D1 d1 = Method1;
D2 D2 = D1; // compile-time error
Delegate instances are considered equal if they have the same method targets:
delegate void D( );...D d1 = Method1;D d2 = Method1;Console.WriteLine (d1 == d2); // true
2) parameter compatibility
When you call a method, you can supply arguments that have more specific types than the parameters of that method. this is ordinary polymorphic behavior. for exactly the same reason, a delegate can have more specific parameter types than its method target. this is calledContravariance.
void SpecificDelegate (SpecificClass s);class SpecificClass {}class Test{ static void Main( ) { SpecificDelegate specificDelegate = GeneralHandler; specificDelegate (new SpecificClass( )); } static void GeneralHandler(object o) { Console.WriteLine(o.GetType( )); // SpecificClass }}
[From small to big]
3) return type compatibility
If you call a method, you may get back a type that is more specific than what you asked. this is ordinary polymorphic behavior. for exactly the same reason, the return type of a delegate can be less specific than the return type of its target method. this is calledCovariance. Consider the following example:
delegate Asset DebtCollector( );class Asset {}class House : Asset {}class Test{ static void Main( ) { DebtCollector d = new DebtCollector (GetHomeSweetHome); Asset a = d( ); Console.WriteLine(a.GetType( )); // House } static House GetHomeSweetHome() {return new House( ); }}
[From big to small]
2. The main purpose of events is to prevent subscribers from interfering with each other.
3. With explicit event accessors, you can apply more complex strategies to the storage and access of the underlying delegate. There are three scenarios where this is useful:
When the event accessors are merely relays for another class that is broadcasting the event
When the class exposes a large number of events, where most of the time very few subscribers exist, such as a Windows Control. in such cases, it is better to store the subscriber's delegate instances in a dictionary, since a dictionary will contain less storage overhead than dozens of null delegate field references
When explicitly implementing an interface that declares an event