2010-07-07 4 views
25

Je me inscris composants avec le code suivant:même instance pour plusieurs interfaces

StandardKernel kernel = new StandardKernel(); 

string currentDirectory = Path.GetDirectoryName(GetType().Assembly.Location) 
foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies()) 
{ 
    if (!Path.GetDirectoryName(assembly.Location).Equals(currentDirectory)) 
     continue; 

    foreach (var type in assembly.GetTypes()) 
    { 
     if (!type.IsComponent()) 
      continue; 

     foreach (var @interface in type.GetInterfaces()) 
     kernel.Bind(@interface).To(type).InSingletonScope(); 
    } 
} 

J'ai une classe qui implémente deux interfaces:

class StandardConsole : IStartable, IConsumer<ConsoleCommand> 

Si je peux résoudre IStartable je reçois un Par exemple, si je résous IConsumer<ConsoleCommand> je reçois un autre.

Comment obtenir la même instance pour les deux interfaces?

+1

Cette question devrait être scindée en deux, une pour Ninject et l'autre pour autofac. –

+0

@JeffWalkerCodeRanger: Vous avez donné -1 pour cela? :) – jgauffin

+1

Il ya 3 ou 4 dups sur le côté Ninject, voir http://stackoverflow.com/questions/3147996/binding-singleton-to-multiple-services-in-ninject Balise ninject supprimée sur cette base. Suggérer de supprimer l'aspect ninject de la question car cela fait une question sans réponse –

Répondre

49
builder.RegisterType<StandardConsole>() 
    .As<IStartable>() 
    .As<IConsumer<ConsoleCommand>>() 
    .SingleInstance(); 

très largement fonction Permettent de Autofac- problème alors il y a un bug quelque part :)

Hth Nick

Modifier Par regarde, vous êtes après la surcharge de As() qui prend un IEnumerable <Type>() - vérifier toutes les surcharges As() en utilisant IntelliSense, quelque chose devrait correspondre à votre scénario. Comme un autre intervenant l'a noté, vous devez mettre à jour la question avec toutes les informations.

+0

Non, je ne veux pas enregistrer en utilisant IEnumerable . C'est une fonction intégrée dans autofac. De plus, je ne peux pas utiliser de paramètres génériques puisque j'utilise la réflexion pour enregistrer tous les composants. – jgauffin

+2

Je connais la fonction que vous voulez dire (je l'ai écrite;)) - celle que je suggère est différente. Si vous avez une liste des interfaces que vous souhaitez exposer (i1, i2, i3 ..) vous pouvez simplement passer la liste entière à un seul appel As(). Vous pouvez également vérifier RegisterAssemblyTypes (myAsm) .AsImplementedInterfaces(), qui peut être étendu pour faire ce que votre article propose http://code.google.com/p/autofac/wiki/Scanning - vous êtes invités à travailler à travers ceci via le forum de discussion Autofac si vous le souhaitez. –

+0

Désolé =) Je suis juste fatigué de la réponse de personnes qui n'avaient pas utilisé autofac. J'ai mis à jour ma réponse ci-dessous avec le code de l'article de numérisation. Merci! – jgauffin

0

Ceci me prend un coup sauvage dans le noir car je ne connais pas Autofac.

Si vous ajoutez:

build.RegisterType<StandardConsole>.As(StandardConsole).SingleInstance() 

alors il ne devrait pas résoudre IStartable à StandardConsole puis StandardConsole à l'instance singleton de StandardConsole? Idem avec IConsumer.

EDIT: De vous connecter à votre blog, ne pourriez-vous changer les éléments suivants:

assemblies.Each(assembly => assembly.FindComponents((i, c) => builder.RegisterType(c).As(i).SingleInstance())); 

à

assemblies.Each(assembly => assembly.FindComponents((i, c) => { 
    builder.RegisterType(c).As(i).SingleInstance(); 
    builder.RegisterType(c).As(c).SingleInstance(); 
})); 
+0

Voir mon commentaire pour dave thieben – jgauffin

0

Je ne suis pas familier avec Autofac, mais vous devriez être en mesure de Enregistrer pour un type une expression lambda qui renvoie la résolution de l'autre type.

quelque chose comme:

builder.Register<IStartable>().As<StandardConsole>().Singleton(); 
builder.Register<IConsumer<ConsoleCommand>>().As(x => builder.Resolve<IStartable>()); 
+1

No can do.Je scanne tous les assemblys dans le répertoire de l'application après les classes avec un ComponentAttribute et les enregistre avec toutes les interfaces qu'ils implémentent. Cela rend assez difficile de faire ce que vous suggérez. http://blog.gauffin.org/2010/07/simplified-autofac-registrations/ – jgauffin

2

Mise à jour avec la suggestion de Nicholas:

Voici comment cela se fait dans autofac

private void BuildComponents(ContainerBuilder builder) 
    { 
     string currentDirectory = Path.GetDirectoryName(GetType().Assembly.Location); 
     foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies()) 
     { 
      if (!Path.GetDirectoryName(assembly.Location).Equals(currentDirectory)) 
       continue; 

      builder.RegisterAssemblyTypes(assembly) 
       .Where(t => t.IsComponent()) 
       .AsImplementedInterfaces() 
       .SingleInstance(); 
     } 
    } 

    public static bool IsComponent(this Type value) 
    { 
     return value.GetType().GetCustomAttributes(typeof (ComponentAttribute), true).Length > 0; 
    } 
2

Je sais que c'est un vieux fil, mais voici la solution pour Ninject.

kernel.Bind<StandardConsole>().ToSelf().InSingletonScope(); 
kernel.Bind<IStartable>().ToMethod(ctx => ctx.Kernel.Get<StandardConsole>()); 
kernel.Bind<IConsumer<ConsoleCommand>>().ToMethod(ctx => ctx.Kernel.Get<StandardConsole>()); 
+0

Cela ne fonctionne pas avec ActivationContext. –

+0

@Jeff: Voir http://www.planetgeek.ch/2011/12/30/new-features-and-changes-of-ninject-3-0/ –

Questions connexes