Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Contravariance in Action lambda - C#

I have a class hierarchy like this

public abstract class CalendarEventBase{}

public class TrainingEvent : CalendarEventBase{}

public class AuditEvent : CalendarEventBase{}

I wanted to create an action Action lamda that had a generic type paramater of type CalendarEventBase that I could assign to the following different methods:

public void EmailCancelation(TrainingEvent trainingEvent)

public void EmailCancelation(AuditEvent auditEvent)

I created the following illegal assignment:

Action<CalendarEventBase> emailCancelation = _trainingService.EmailTrainingCancellation;

The compiler complains that it was expecting a method with void(CalendarEventBase) as a signature. I was surprised by this as I thought it would accept a more derived type.

To get round this, I created the following delegate that allows me to complete my task:

public delegate void EmailCancelation<in T>(T calendarEvent) where T : CalendarEventBase;

My question is, could I have completed the task without having to create an additional delegate? I thought I could just create an Action instance.

Any help or pointers, greatly appreciated.

like image 658
dagda1 Avatar asked Feb 11 '11 11:02

dagda1


1 Answers

The line:

Action<CalendarEventBase> emailCancelation = _trainingService.EmailTrainingCancellation;

is actually expecting covariance, not contravariance. But that logically doesn't make sense; the method expects a TrainingEvent as input - how can you pass a more general type (CalendarEventBase) to it?

This isn't legal:

// What if the method wants to make the lion roar but you pass in a goat?
Action<Mammal> mammalAction = MethodThatTakesALion; 

but this is fine:

// Anything that you want to with an animal, you can do with a mammal.
Action<Mammal> mammalAction = MethodThatTakesAnAnimal; 
like image 86
Ani Avatar answered Sep 19 '22 21:09

Ani