- How to cast generic interfaces using contravariant parameters to a base type?
- using System;
- using System.Diagnostics;
- namespace ConsoleApplication2
- {
- // Command classes
- public class CommandMessage
- {
- public DateTime IssuedAt { get; set; }
- }
- public class CreateOrderMessage : CommandMessage
- {
- public string CustomerName { get; set; }
- }
- // Covariant solution
- public interface ICommandMessageHandler1<out T> where T : CommandMessage
- {
- void Execute(CommandMessage command);
- }
- public class CreateOrderHandler1 : ICommandMessageHandler1<CreateOrderMessage>
- {
- public void Execute(CommandMessage command)
- {
- // An explicit typecast is required
- var createOrderMessage = (CreateOrderMessage) command;
- Debug.WriteLine("CustomerName: " + createOrderMessage.CustomerName);
- }
- }
- // Contravariant attempt (doesn't work)
- public interface ICommandMessageHandler2<in T> where T : CommandMessage
- {
- void Execute(T command);
- }
- public class CreateOrderHandler2 : ICommandMessageHandler2<CreateOrderMessage>
- {
- public void Execute(CreateOrderMessage command)
- {
- // Ideally, no typecast would be required
- Debug.WriteLine("CustomerName: " + command.CustomerName);
- }
- }
- class Program
- {
- static void Main(string[] args)
- {
- var message = new CreateOrderMessage {CustomerName = "ACME"};
- // This code works
- var handler1 = new CreateOrderHandler1();
- ICommandMessageHandler1<CreateOrderMessage> handler1b = handler1;
- var handler1c = (ICommandMessageHandler1<CommandMessage>) handler1;
- handler1c.Execute(message);
- // This code throws InvalidCastException
- var handler2 = new CreateOrderHandler2();
- ICommandMessageHandler2<CreateOrderMessage> handler2b = handler2;
- var handler2c = (ICommandMessageHandler2<CommandMessage>)handler2; // throws InvalidCastException
- handler2c.Execute(message);
- }
- }
- }
- public class CommandMessage
- {
- public DateTime IssuedAt
- {
- get;
- set;
- }
- }
- public class CreateOrderMessage : CommandMessage
- {
- public string CustomerName
- {
- get;
- set;
- }
- }
- public interface ICommandMessageHandler2<in T> where T : CommandMessage
- {
- void Execute(T command);
- }
- public class CreateOrderHandler2 : ICommandMessageHandler2<CreateOrderMessage>
- {
- public void Execute(CreateOrderMessage command)
- {
- // No typecast is required
- Debug.WriteLine("CustomerName: " + command.CustomerName);
- }
- }
- class Program
- {
- static void Main(string[] args)
- {
- var message = new CreateOrderMessage
- {
- CustomerName = "ACME"
- };
- // This code throws InvalidCastException
- var handler2 = (ICommandMessageHandler2<CreateOrderMessage>)new CreateOrderHandler2();
- handler2.Execute(message);
- }
- }