J'essaie de développer un processeur de commande générique. Je voudrais créer des classes de gestionnaires de commandes implémentant une interface donnée. J'utiliserai l'inversion de contrôle pour créer de manière dynamique une instance de la classe appropriée en fonction du type de commande reçue. J'aimerais ensuite appeler la méthode "Execute" de la classe de manière générique.
Je suis capable de faire fonctionner cela en utilisant un paramètre de type covariant mais dans ce cas, je ne peux pas utiliser le paramètre de type générique comme paramètre de méthode.
Il semblerait qu'une approche contravariante devrait fonctionner, car elle me permet de déclarer les paramètres de la méthode comme je le souhaite, mais malheureusement l'instance de la classe ne peut pas être convertie en interface de base.
Le code ci-dessous illustre le problème :
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);
}
}
}