2010-01-11 3 views
2

Je suis nouveau à Windsor, mais je suis certain qu'il doit y avoir un moyen de le faire ...Choisir le bon constructeur en utilisant un fichier de configuration externe à Windsor?

J'ai une classe avec trois constructeurs différents:

public MyClass(string SomeParam) 
{ 
... 
} 

public MyClass(string AnotherParam, string YetAnother) 
{ 
... 
} 

public MyClass(string AnotherOne, string YeahIKnow, string AnnoyingExampleParam) 
{ 
... 
} 

Dans mon fichier de configuration externe , j'ai mon service défini comme:

<component 
    id="IMyClass" 
    service="IMyInterface, MyAssembly" 
    type="MyClass, MyOtherAssembly"> 

    <parameters> 
    <AnotherOne>string value #1</AnotherOne> 
    <YeahIKnow>string value #2</YeahIKnow> 
    <AnnoyingExampleParam>string value #3</AnnoyingExampleParam> 
    </parameters> 

</component> 

lorsque Windsor initialise une instance de ma classe, il ne veut initialiser en utilisant le premier (seul paramètre de chaîne) constuctor de ma classe, quand je veux vraiment Windsor utiliser la troisième constructeur. Je ne vois rien dans les docs à propos de forcer le noyau à nous un constructeur particulier en utilisant une configuration externe, même si je peux trouver des références pour le faire en code, mais ce genre de défaites l'objectif d'une configuration externe !

Tout conseil serait apprécié.

Best,

David Montgomery

+2

L'attribut type dans l'élément component manque l'assembly (et éventuellement l'espace de nom). Est-ce une faute de frappe? –

+0

Oui, c'était une faute de frappe. –

Répondre

1

Quelle version de Castle? Je me souviens, du fond de ce qui se passe pour ma mémoire à 4 heures du matin, qu'il y avait une résolution pour le travail de constructeur dans Castle 2.0.

Humm, la mémoire revient un peu maintenant ... Quelque chose me dit que Castle va construire l'objet avec le premier ctor public. Peut être aussi simple que de déplacer ce que vous voulez pour Castle à charger, vers le haut.

Si cela ne fonctionne pas pour vous, peut-être refactoriser votre code un peu?

Option 1) Rendre internes les deux premiers constructeurs.

Option 2) Utilisez un motif Factory pour vos objets complexes, qui utilisera Castle sur le backend pour réécrire la version plus simple ou plus complexe.

Option 3) Créez 3 classes à partir de votre super-classe de base, chacune ayant un constructeur plus compliqué. De cette façon, vous pouvez spécifier précisément dans le fichier de configuration de Castle quel service charger. Par exemple:

public abstract class BaseClass 
{ 
    public BaseClass(String requiredParam) 
    { 
    ... 
    } 
} 

public class SimpleClass : BaseClass 
{ 
    public SimpleClass(String requiredParam, String anotherParam) 
    : base(requiredParam) 
    { 
    ... 
    } 
} 


public class MoreComplexClass : SimpleClass 
{ 
    public MoreComplexClass (String requiredParam, String anotherParam, String yetAnother) 
    : base(requiredParam, anotherParam) 
    { 
    ... 
    } 
} 

Mais, je n'ai pas encore rencontré cela. Principalement parce que je m'en tiens à seulement 1 ctor public sur mes cours, avec quelques cteurs privés/internes pour des choses telles que Linq pour recréer mes objets avec un ctor vide (puisque Linq ne supporte pas Dependency Injection, boo). Notez que dans cette dernière déclaration, les agents internes, que mon SRP (Single Responsibility Pattern) pour résoudre mes composants IoC est externe, dans un ensemble higharchy séparé (c'est-à-dire une application ou une couche d'interface utilisateur). Comme il n'est pas interne aux objets de mon domaine, les agents internes ne sont pas vus par Castle.

+0

Salut, j'utilise 2.0. Changer mes constructeurs via une classe wrapper fonctionne pour moi en ce moment, même si cela ressemble à un hack sale. –

+0

Faire une classe wrapper juste pour avoir le bon constructeur est un hack sale, et pas tout à fait ce que je voulais. Je suggérais une séparation de la préoccupation par le paramètre 3 pour une classe différente avec des exigences différentes. Qu'en est-il juste de déplacer le paramètre 3 en haut de la liste? – eduncan911

+0

Je pense que le modèle d'usine est certainement la bonne façon de faire (merci pour la pointe BTW). Changer l'ordre des constructeurs (ou modifier les constructeurs en ajoutant un faux paramètre comme je l'ai fait) reposerait sur le mécanisme de notation de Castle pour rester indéfiniment constant - ce qui est un détail d'implémentation que j'espère oublier et ne plus jamais retenir! –

0

Vous devez faire quelque chose de mal. Windsor utilise le constructeur le plus gourmand qu'il peut satisfaire. Si elle utilise le plus petit, vous avez peut-être une faute de frappe?

lorsque votre type est le service, vous ne devez pas spécifier les deux

service="MyClass, MyAssembly" 
    type="MyClass"> 

retirer le type.

+0

Désolé, mon exemple XML était mauvais. Ce qui précède est correct à titre d'exemple. –

+0

Je suis d'accord, que "je fais quelque chose de mal" est probablement la question à portée de main, mais ... le code trouvé à http://fisheye2.atlassian.com/browse/castleproject/trunk/InversionOfControl/Castle.MicroKernel/ ComponentActivator/DefaultComponentActivator.cs? R = 5806 # l204 semble renvoyer le premier constructeur à un seul argument en tant que constructeur approprié. Je pourrais lire ceci plutôt faux cependant. De mon test, si je change la signature de mon premier constructeur pour avoir un deuxième paramètre, ma configuration fonctionne comme je l'attendais. –

+0

non, ça ne marche pas vraiment comme ça. Il commence par le constructeur le plus gourmand et descend (nombre de paramètres WRT) jusqu'à ce qu'il trouve celui qu'il peut satisfaire. Dans votre cas, il devrait commencer par le paramètre 3 et être capable de l'utiliser. Je vais jeter un oeil –

Questions connexes