C# language feature:
applies to
benefit
The method passed to a delegate may now have greater flexibility in its return type and parameters.
note
how to use CoVariance
how to use ContraVariance
ContraVariance note
example:
// declare base class and derived classes
class mybase
{
}
class derived : mybase
{
}
class derived2times : derived
{
}
class CoVariance_Example
{
// declare delegates with varying returned typess
public delegate mybase Delegate_Returns_Base_Type(); // accepts methods with base/defined and derivitive return types!
public delegate derived Delegate_Returns_Derived_Type(); // accepts methods with derived/defined and derivitive return types!
public delegate derived2times Delegate_Return_Derived2Times_Type(); // accepts methods with derived2times/defined and derivitive return types if any!
// declare methods/functions
public static mybase MethodReturnsBase()
{
return new mybase();
}
public static derived MethodReturnsDerived()
{
return new derived();
}
public static derived2times MethodReturnsDerived2times()
{
return new derived2times();
}
void Use_of_CoVariance_Example()
{ // assign some delegates
// NOTICE- delegate type CAN accept signatures with returnr objects from base/defined and derivatives i.e. descendants, this is co-variance!
Delegate_Returns_Base_Type handler_accepts_base_return = MethodReturnsBase;
Delegate_Returns_Base_Type handler_accepts_base_return2 = MethodReturnsDerived;
Delegate_Returns_Base_Type handler_accepts_base_return3 = MethodReturnsDerived2times;
// Delegate_Returns_Derived_Type handler_accepts_derived_return = MethodReturnsBase; // illegal can not accept less derived type than Delegate_Returns_Derived_Type
Delegate_Returns_Derived_Type handler_accepts_derived_return2 = MethodReturnsDerived;
Delegate_Returns_Derived_Type handler_accepts_derived_return3 = MethodReturnsDerived2times;
//Delegate_Return_Derived2Times_Type handler_accepts_derived2times_return = MethodReturnsBase; // illegal can not accept less derived type than Delegate_Return_Derived2Times_Type
//Delegate_Return_Derived2Times_Type handler_accepts_derived2times_return2 = MethodReturnsDerived; //
Delegate_Return_Derived2Times_Type handler_accepts_derived2times_return3 = MethodReturnsDerived2times;
}
}
class ContraVariance_Example
{
// declare delegates with varying parameter types
public delegate mybase Delegate_Accepts_Base_Parameter(mybase c); // very limited accepts methods with base parameters defined!
public delegate mybase Delegate_Accepts_Derived_Parameter(derived c); // accepts methods with (derived or base) parameters defined
public delegate mybase Delegate_Accepts_Derived2Times_Parameter(derived2times c); // accepts methods with (derived2times or derived or base) parameters defined
static event Delegate_Accepts_Derived_Parameter onEventDerived; // declare an event
// declare methods/functions
public static mybase MethodAcceptsBase(mybase b)
{
return b;
}
public static mybase MethodAcceptsDerived(derived d)
{
return d as mybase;
}
public static mybase MethodAcceptsDerived2times(derived2times d2)
{
return d2 as mybase;
}
void Use_of_ContraVariance_Example()
{ // assign some delegates
Delegate_Accepts_Base_Parameter handler_accepts_base_parameter = MethodAcceptsBase; // legal
// NOTICE- delegate type can NOT accept signatures with derived parameter objects (i.e. descendents like below!)
// Delegate_Accepts_Base_Parameter handler_accepts_base_parameter2 = MethodAcceptsDerived; // illegal cannot accept more derived parameter signature than Delegate_Accepts_Base_Parameter
// Delegate_Accepts_Base_Parameter handler_accepts_base_parameter3 = MethodAcceptsDerived2times; // illegal cannot accept more derived parameter signature than Delegate_Accepts_Base_Parameter
// ***
// NOTICE- delegate type CAN accept signatures with parameter objects from defined to base i.e. ancestors, this is contra-variance!
Delegate_Accepts_Derived_Parameter handler_accepts_derived_parameter = MethodAcceptsBase; //legal
Delegate_Accepts_Derived_Parameter handler_accepts_derived_parameter2 = MethodAcceptsDerived; //legal
//Delegate_Accepts_Derived_Parameter handler_accepts_derived_parameter3 = MethodAcceptsDerived2times; // illegal cannot accept more derived parameter signature than Delegate_Accepts_Derived_Parameter
// All legal by contravariance! that is, DELEGATE accepts antecedent signature methods
Delegate_Accepts_Derived2Times_Parameter handler_accepts_derived2times_parameter = MethodAcceptsBase;
Delegate_Accepts_Derived2Times_Parameter handler_accepts_derived2times_parameter2 = MethodAcceptsDerived;
Delegate_Accepts_Derived2Times_Parameter handler_accepts_derived2times_parameter3 = MethodAcceptsDerived2times;
// On to events...
onEventDerived += new Delegate_Accepts_Derived_Parameter(handler_accepts_base_parameter); //legal
onEventDerived += new Delegate_Accepts_Derived_Parameter(handler_accepts_derived_parameter); //legal
//onEventDerived += new Delegate_Accepts_Derived_Parameter(handler_accepts_derived2times_parameter); // illegal signature must be less derived!
//onEventDerived.Invoke(new mybase()); //illegal as parameter can not be up derived!
onEventDerived.Invoke(new derived());
onEventDerived.Invoke(new derived2times());
// In conclusion, in explaining contra-variance of event handlers, the event handlers
// are able to assign/use contra-variance to call a delegate with an base/antecedent signature
// also note, a more "derived signature" would not make sense as that implies a derived/descendent
// object that the handler does not "understand" or is capable of producing.
}
}