2009-09-17 12 views
12

Je suis une interface comme celui-ciStructureMap, constructeur qui prend une liste de plugins

public interface IWriter 
{ 
    ... 
} 

et une classe

public class WriterMerger 
{ 
    public WriterMerger(IEnumerable<IWriter> writers) 
    ... 
} 

Je veux StructureMap remplir l'argument du constructeur sur WriterMerger avec tous iWriter enregistrés de . Je enregistré les différents écrivains avec

StructureMap.ObjectFactory.Initialize(x => 
{ 
    x.ForRequestedType<IWriter>().AddConcreteType<MemoryWriter>(); 
    x.ForRequestedType<IWriter>().AddConcreteType<FlatFileWriter>(); 
    x.ForRequestedType<IWriter>().AddConcreteType<DbWriter>(); 
} 

cependant appeler

ObjectFactory.CreateInstance<WriterMerger>(); 

Renvoie une exception « Aucune instance par défaut défini pour PluginFamily System.Collections.Generic.IEnumerable`1 [[iWriter ..]] " (nom de classe modifié)

Un truc pour faire cela automatiquement? ou devrais-je faire une méthode d'usine personnalisée?

Répondre

10

Lorsque vous voulez tous les cas concrets d'un type à injecter, vous devez déclarer le paramètre comme un tableau. Vous pouvez résoudre votre problème en changeant votre constructeur à:

public WriterMerger(IWriter[] writers) 

Soyez conscient que les outils de nettoyage de code comme ReSharper peut mettre en évidence le tableau dans votre constructeur et vous suggérez le remplacer par IEnumerable, si c'est tout ce qui est requis par votre WriterMerger. Cependant, ces outils ne sont pas conscients de l'obligation de StructureMap d'utiliser un tableau, vous devez donc l'ignorer.

Vous pouvez également savoir que vous pouvez enregistrer automatiquement tous vos IWriters, au lieu de les répertorier explicitement. Il suffit de changer la configuration de votre conteneur:

StructureMap.ObjectFactory.Initialize(x => 
{ 
    x.Scan(scan => 
    { 
     scan.TheCallingAssembly(); 
     scan.AddAllTypesOf<IWriter>(); 
    }); 
}); 

Il y a un certain nombre de différentes options de numérisation qui vous permettent de numériser différents ensembles, exclure certains types, etc.

1

Je pense que ce que cela vous dit, c'est que vous devez définir l'un de ces IWriters par défaut. Imaginez une autre classe avait l'contructor suivante:

public class Test{ 
    public Test(IWriter writer){} 
} 

Sans défaut iWriter il ne connaîtrait pas que l'écrivain à attribuer. Donc, vous avez probablement besoin de dire quelle est la valeur par défaut même si vous ne l'utilisez jamais. Voir ce post:

What's the difference between AddConcreteType and TheDefaultIsConcreteType in StructureMap?

2

Je dupliqués votre problème et je crois que votre le code fonctionnera si vous changez votre classe consommatrice d'IWriter pour avoir un ctor qui prend un tableau d'IWriter.

public class WriterMerger { public WriterMerger(IWriter[] writers) } 

Josh est juste sur à recommander une meilleure façon d'enregistrer tous les types de iWriter avec StructureMap. Scanners FTW.

+0

Merci, qui a résolu mon problème – AndreasN

18

En fait, cela peut être fait sans changer votre constructeur

Changer la configuration de votre conteneur:

StructureMap.ObjectFactory.Initialize(x => 
{ 
    x.Scan(scan => 
    { 
     scan.TheCallingAssembly(); 
     scan.AddAllTypesOf<IWriter>(); 
    }); 
    x.ForRequestedType<IEnumerable<IWriter>>() 
     .TheDefault.Is.ConstructedBy(x => ObjectFactory.GetAllInstances<IWriter>()); 
}); 
+0

Même si cela nécessite un peu plus de spécification, cette approche est moins couplée à L'exigence de StructureMap pour spécifier la collection comme un tableau et obtient donc un +1 de moi. –

+0

Pour ceux qui utilisent SM3, il semble que 'ForRequestedType <>' ait été supprimé. –

+0

Je n'ai pas utilisé SM depuis un moment mais je crois que ForRequestedType <> est maintenant juste pour <> –