How to delegate the correct <Interfaces> action?

I start with C # and cannot find the answer for this:

I try to delegate actions with some interface parameter, but I push functions with objects that extend this interface (or class)

 // some class extending interface public class IntEvent : IFace{} public class MoveEvent : IFace{} // function i like to use to verify Action static void setAction(Action<IFace> evt) { // evt ... } // function to delegate as Action static void evtCheck(IntEvent evt) { // some func } static void evtMove(MoveEvent evt) { // some func } // class { // call method inside class and delegate this function : setAction(evtCheck); setAction(evtMove); 

I get the error message " evtCheck(IntEvent) cannot be converted to Action<IFace> ", even if IntEvent extends the IFace interface.

How do i solve this? Maybe I need to use Func or Delegate?

+6
source share
2 answers

You cannot do what you are trying to do - you expect covariance, but Action<T> contravariant only on its parameter type.

You cannot convert a group of methods from evtCheck to Action<IFace> because evtCheck requires a more specific type ( IntEvent ) as an argument than the more general IFace type that the Action<IFace> instance expects. If such a conversion were allowed, what would you expect if the delegate was executed with an argument that implements IFace but is not an IntEvent ?

I think you need to take a look at your design again, because it seems like there is a flaw there, but if you want, you can create a lambda to force the composition of the argument to the given type and accept the InvalidCastException :

 setAction(iFace => evtCheck((IntEvent)iface)); 

Most likely, you might want to make evtCheck more general type or setAction to accept a more specific delegate.

+7
source

Action<T> is contravariant in T, so methods that take Action<T> also accept Action<U> , where T derives from U.

However, your IntEvent class implements the IFace interface, which means that if the compiler accepted your call to setAction() , you could call evtCheck() with an argument that is another IFace - a derivative, not an IntEvent , a runtime error and an obvious security violation like .

Required Link Eric Lippert: Covariance and Contravariance

EDIT: from your description, it seems to me that what you really want is differentiation based on the type of the method parameter, i.e. you need a separate action for IntEvent , another for (hypothetical) DoubleEvent , etc. If so, you are in fact after a double virtual submit, which is not supported directly in C #, but you can simulate it using the Visitor design template.

+4
source

Source: https://habr.com/ru/post/917729/


All Articles