2010-03-31 7 views
2

Comment puis-je utiliser StructureMap pour résoudre une implémentation appropriée d'une interface basée sur un nom stocké dans un attribut?Utiliser StructureMap pour créer des classes par un nom?

Dans mon projet, j'ai beaucoup de différents types de widgets, chacun descendant de IWidget, et chacun décoré avec un attribut spécifiant le type d'élément associé.

À titre d'illustration:

[Configuration("header")] 
public class HeaderWidget : IWidget { } 

[Configuration("linegraph")] 
public class LineGraphWidget : IWidget { } 

Lors du traitement de mon fichier de configuration (XML), je veux obtenir une instance de la classe concrète appropriée en fonction du nom de l'élément que je suis le traitement. Chaque définition doit aboutir à la création d'un widget différent - je n'ai pas besoin ou je ne veux pas que les instances soient partagées. Dans le passé, j'ai écrit beaucoup de code pour faire ce genre de chose manuellement, y compris l'écriture d'un conteneur IoC personnalisé "roll-your-own" pour un projet. Cependant, un de mes objectifs avec ce projet est de devenir compétent avec StructureMap au lieu de réinventer la roue.

Je pense que je l'ai déjà réussi à mettre en place l'analyse automatique des assemblages de sorte que StructureMap connaît tous mes implémentations IWidget:

public class WidgetRegistration : Registry 
{ 
    public WidgetRegistration() 
    { 
     Scan(
      scanner => 
      { 
       scanner.AssembliesFromApplicationBaseDirectory(); 
       scanner.AddAllTypesOf<IWidget>(); 
      }); 
    } 
} 

Cependant, ce n'enregistre les noms de mes widgets avec StructureMap. Que dois-je ajouter pour que mon scénario fonctionne?

(Alors que je suis en train d'utiliser StructureMap dans ce projet, une réponse me montrant comment résoudre ce problème avec un outil DI/IoC différent serait toujours valable.)

Mise à jour

I « m assez sûr que le côté de la consommation implique d'appeler GetNamedInstance comme ceci:

public IWidget CreateWidget(XElement definition) 
{ 
    var kind = definition.Name.LocalName; 
    var widget = ObjectFactory.GetNamedInstance<IWidget>(kind); 
    widget.Configure(definition); 
    return widget; 
} 

Ainsi, le morceau restant du puzzle est comment enregistrer automagiquement les types dans mon WidgetReg classe d'isolation.

Répondre

1

est ici où je me suis retrouvé - tours Tout ce dont j'avais besoin est supporté par StructureMap.

Ma classe d'inscription prend soin de tout le sale boulot:

public class DashboardRegistration : Registry 
{ 
    public DashboardRegistration() 
    { 
     Scan(
      scanner => 
      { 
       scanner.AssembliesFromApplicationBaseDirectory(); 
       scanner.AddAllTypesOf<IDisplay>() 
        .NameBy(DashboardXml.DisplayElement); 
       scanner.AddAllTypesOf<IDataSource>() 
        .NameBy(DashboardXml.DataSourceElement); 
      }); 
    } 
} 

Le .NameBy() prend un délégué qui fournit le nom souhaité.

Les méthodes appropriées sur le look de classe DashboardXml comme celui-ci (code abrégé):

public static class DashboardXml 
{ 
    ... 

    public static string DataSourceElement(Type type) 
    { 
     const string DataSourceSuffix = "DataSource"; 

     string result = type.Name; 
     if (result.EndsWith(DataSourceSuffix)) 
     { 
      result 
       = result.Substring(0, result.Length - DataSourceSuffix.Length); 
     } 

     return result.ToLowerInvariant(); 
    } 

    public static string DisplayElement(Type type) 
    { 
     const string DisplaySuffix = "Display"; 

     string result = type.Name; 
     if (result.EndsWith(DisplaySuffix)) 
     { 
      result 
       = result.Substring(0, result.Length - DisplaySuffix.Length); 
     } 

     return result.ToLowerInvariant(); 
    } 
} 
1

Nous avons implémenté un scanner personnalisé:

public class WidgetScanner : ITypeScanner 
{ 
    public void Process(Type type, PluginGraph graph) 
    { 

Ensuite, utilisez scan:

 Scan(y => 
     { 
      y.AddAllTypesOf(typeof(IWidget)); 
      y.Assembly(Assembly.GetExecutingAssembly().FullName); 
      y.With<WidgetScanner>(); 
     }); 

..et pour obtenir une instance:

_container.GetInstance<IWidget>(name) 
+0

une réponse utile (+1), bien que je ne l'ai pas besoin de mettre en œuvre mon propre scanner dans ma propre situation. – Bevan

Questions connexes