I'm looking for a delegate that encapsulates a method that return no value and take one parameter, like Action< T > does, but unfortunately that delegate does not match with method taking a child type as parameter...
That's what I'm trying to do:
public class BaseType
{
public BaseType()
{
}
}
public class ChildType : BaseType
{
public ChildType()
{
}
}
public class Test
{
public delegate void CallBackHandler(BaseType p);
public Test()
{
CallBackHandler clbk1 = callBackA;
CallBackHandler clbk2 = callBackB; //That line does not compile
//->'No overload for 'callBackB' matches delegate 'Test.CallBackHandler'
}
private void callBackA(BaseType p)
{
}
private void callBackB(ChildType p)
{
}
}
I read about covariance, contravariance, etc... I know it deals with the herited type casting but I'm a little bit confused about all of this...
Which delegate should I use to make my code work ?
This is the classic type safety problem that strong typing was created to solve.
Here's an example
abstract class Vehicle
{
public virtual void MethodSlot1_StartEngine() { }
public virtual void MethodSlot2_StopEngine() { }
}
class Car : Vehicle
{
public virtual void MethodSlot3_OpenGasTank() { }
}
class NuclearSubmarine : Vehicle
{
public virtual void MethodSlot3_FireAllNuclearMissiles() { }
}
class VehicleUser
{
public delegate void OpenGasTankMethod(Car car);
public void OpenGasTank(Vehicle vehicle, OpenGasTankMethod method)
{
//it's stopping you here from firing all nuclear weapons
//by mistaking your car's gas tank for the armageddon switch
method(vehicle);
}
}
When the compiler emits a virtual method call it just compiles an index into a lookup table. If you could pass in a NuclearSubmarine where a Car is required merely because they are both Vehicles, then you could think you are calling Car methods (like opening your gas tank) when in fact you are just making the Fallout series of games a reality.
In response to your comment, this should get you started:
class Blah
{
private List<Action<object>> _handlers = new List<Action<object>>();
public void AddListener<T>(Action<T> handler)
{
//graceful type checking code goes in here somewhere
_handlers.Add(o => handler((T) o));
}
void RaiseEvent(object eventArgs)
{
foreach (var handler in _handlers) handler(eventArgs);
}
}