2011-08-08 1 views
1

Je ne sais pas comment formuler cette question, car je ne sais pas où se situe le problème. Je pense que c'est un problème de covariance générique, mais la solution pourrait être trouvée ailleurs, peut-être dans la façon dont les interfaces sont conçues, ou dans la façon dont les implémentations sont enregistrées.Enregistrement automatique et résolution des types implémentant un interace générique

Quoi qu'il en soit, l'échantillon tente d'enregistrer tous les types implémentant une interface générique, puis de résoudre le type en utilisant le type du générique. Ensuite, essayez de convertir ce type en son type de base pour pouvoir appeler une méthode sur cette implémentation.

Son échec maintenant en essayant de lancer. A titre d'exemple, la première ligne de code ne parvient pas à compiler. Une fois supprimé, le programme échoue sur la ligne essayant de lancer l'implémentation.

class Program 
{ 
    private static IContainer _container; 

    static void Main(string[] args) 
    { 
     // Is this the problem? 
     IHandler<IConfiguration> test = new MyHandler(); 

     // setup ioc 
     var builder = new ContainerBuilder(); 
     builder.RegisterAssemblyTypes(typeof(Program).Assembly) 
      //.Where(t => typeof(IHandler<IConfiguration>).IsAssignableFrom(t)); 
      .Where(t => t.GetInterfaces() 
       .Where(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IHandler<>)) 
       .Any() 
       ) 
      .As(t => t.GetInterfaces() 
       .Where(i => i.GetGenericTypeDefinition() == typeof(IHandler<>)) 
       .Single() 
      ); 
     _container = builder.Build(); 

     // get my configuration impl 
     var configuration = new MyConfiguration(); 

     // resolve handler for the configuration 
     var configurationType = configuration.GetType(); 
     var handlerGenericType = typeof(IHandler<>); 
     var handlerType = handlerGenericType.MakeGenericType(configurationType); 
     var handler = _container.Resolve(handlerType); 
     var typedHandler = (IHandler<IConfiguration>) handler; 

     // handle it! 
     typedHandler.Handle(configuration); 
    } 
} 

public interface IConfiguration 
{ 
} 

public interface IHandler<T> where T : IConfiguration 
{ 
    void Handle(T myConfiguration); 
} 

public class MyConfiguration : IConfiguration 
{ 
} 

public class MyHandler : IHandler<MyConfiguration> 
{ 
    public void Handle(MyConfiguration myConfiguration) 
    { 
     Console.WriteLine("Handling my stuff..."); 
    } 
} 

Répondre

2

Il n'y a aucun moyen que cela fonctionne.
Voici la raison pour laquelle:
Un IHandler<IConfiguration> nécessite un IConfiguration comme paramètre à Handle.
Si votre première ligne serait valide, ce qui suit compilerions:

MyOtherConfiguration config = new MyOtherConfiguration(); 
IHandler<IConfiguration> test = new MyHandler(); 
test.Handle(config); 

De toute évidence, ce n'est pas correct, parce que MyHandler.Handle veut un type MyConfiguration ou dérivé.

En utilisant contre-variance comme décrit dans ma version antérieure de cette réponse vous permettra de faire ce qui suit:

IHandler<MyDerivedConfiguration> test = new MyHandler(); 

avec MyDerivedConfiguration étant dérivé de MyConfiguration.

+0

Essayé cela, et il ne fonctionne toujours pas. Essayé T également, puis l'attribution fonctionne, mais pas l'implémentation du gestionnaire ne compilera pas. – MatteS

+0

@MatteS: Vous avez raison. Veuillez voir la réponse mise à jour. –

+0

Merci beaucoup, maintenant c'est complètement clair pour moi pourquoi cela ne marche pas. Je pense qu'il faut repenser mon design. Ou sinon, c'est peut-être faisable d'appeler mon gestionnaire en utilisant la réflexion. – MatteS

Questions connexes