Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to delegate correct Action<Interface>?

I'm a beginner with C# and can't find any answer for this :

Im trying to delegate Actions with some interface parameter , but push through 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'm receiving an error that "evtCheck(IntEvent) cannot be converted to Action<IFace>" , even if IntEvent extends the IFace interface .

How should I solve this ? Maybe I have to use Func or Delegate ?

like image 389
turbosqel Avatar asked Jun 10 '12 15:06

turbosqel


People also ask

What is delegate in interface?

Interface delegation, in Kotlin, is a simple yet powerful technique that allows a class to delegate the actual implementation of the interfaces, to separate objects.

CAN interface have delegates?

Interface can be inherited and implemented by any class and a Delegate can be created for a method on any class, as long as the method suits the method signature of the delegate.

How do you call an Action delegate in C#?

You can initialize an Action delegate using the new keyword or by directly assigning a method: Action<int> printActionDel = ConsolePrint; //Or Action<int> printActionDel = new Action<int>(ConsolePrint); An Action delegate can take up to 16 input parameters of different types.

Can we use delegate in interface C#?

It contains both methods and properties. It can be applied to one method at a time. If a class implements an interface, then it will implement all the methods related to that interface. If a delegate available in your scope you can use it.


2 Answers

You can't do what you're trying to do - you're expecting covariance, but Action<T> is contravariant on its only type-parameter.

You can't do a method-group conversion from evtCheck to Action<IFace> because evtCheck needs a more specific type (IntEvent) as its argument than the more general IFace type that an Action<IFace> instance expects. If such a conversion were allowed, what would you expect to happen if the delegate were executed with an argument that implements IFace but is not an IntEvent?

I think you should have another look at your design because it looks like there's a flaw there, but if you want, you can create a lambda to force a cast of the argument to the desired type and accept the possibility of an InvalidCastException:

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

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

like image 96
Ani Avatar answered Oct 01 '22 01:10

Ani


Action<T> is contravariant in T, so methods taking an Action<T> will also accept Action<U> where T is derived from U.

Your IntEvent class, however, implements the IFace interface, which means that if the compiler accepted your setAction() call, it would be possible to call evtCheck() with an argument that is another IFace-derivative and not IntEvent, a runtime error and a clear violation of type safety.

Obligatory Eric Lippert reference: Covariance and contravariance

EDIT: from your description it seems to me that what you really want is differentiation based on the method parameter's type, so e.g. you want a separate action for IntEvent, another one for (a hypothetical) DoubleEvent etc. If this is the case, you are actually after double virtual dispatch, which is not directly supported in C#, but you can simulate it using the Visitor design pattern.

like image 42
Alan Avatar answered Oct 01 '22 01:10

Alan