Pfeh, j'ai trouvé une réponse. Probablement pas la meilleure, mais au moins quelque chose pour commencer.
Regardez l'exemple complet suivant : (j'ai utilisé NInject pour cela) :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Ninject.Core;
using Ninject.Core.Parameters;
using Ninject.Conditions;
namespace IoCTest01
{
interface IA { }
interface IB : IA { }
interface IC : IA { }
abstract class A : IA { }
class B : A, IB
{
public B(IY x)
{
Console.WriteLine("Constructor for B called!");
}
}
class C : A, IC
{
public C(IZ x)
{
Console.WriteLine("Constructor for C called!");
}
}
interface IX { }
interface IY : IX { }
interface IZ : IX { }
abstract class X : IX { }
class Y : X, IY
{
}
class Z : X, IZ
{
}
class TestModule : StandardModule
{
public override void Load()
{
Bind<IY>().To<Y>();
Bind<IZ>().To<Z>();
Bind<IA>().To<B>().Only(When.Context.Parameter<ConstructorArgumentParameter>("x").Matches(
e =>
{
return e.Value.GetType().Equals(typeof(Y));
}));
Bind<IA>().To<C>().Only(When.Context.Parameter<ConstructorArgumentParameter>("x").Matches(
e =>
{
return e.Value.GetType().Equals(typeof(Z));
}));
}
}
class Program
{
static void Main(string[] args)
{
IKernel kernel = new StandardKernel(new TestModule());
IX x1 = kernel.Get<IY>();
IX x2 = kernel.Get<IZ>();
kernel.Dispose();
// lots of code
kernel = new StandardKernel(new TestModule());
var parameters = new ParameterCollection();
parameters.Add<ConstructorArgumentParameter>(new ConstructorArgumentParameter("x", x1));
kernel.Get<IA>(parameters);
parameters = new ParameterCollection();
parameters.Add<ConstructorArgumentParameter>(new ConstructorArgumentParameter("x", x2));
kernel.Get<IA>(parameters);
}
}
}
Lorsqu'il est exécuté, il affiche :
Constructor for B called!
Constructor for C called!
Tout d'abord, j'ai dû injecter manuellement les objets x1 et x2 déjà instanciés dans les appels kernel.Get. Cela semblait suffisant pour permettre à NInject de résoudre la bonne entité, mais dès que j'ai ajouté un deuxième Binding pour IA, il s'est plaint des multiples bindings par défaut pour IA. J'ai donc dû faire une liaison contextuelle :
Bind<IA>().To<B>().Only(When.Context.Parameter<ConstructorArgumentParameter>("x").Matches(
e =>
{
return e.Value.GetType().Equals(typeof(Y));
}));
Ceci vérifie si le paramètre x est de type Y. Si oui, cette liaison est utilisée.
Encore une fois, bien que ce soit une solution, elle est probablement loin d'être optimale. Je souhaite que NInject puisse résoudre le bon type (B ou C) à instancier à partir du type dynamique (Y ou Z) du paramètre donné (x).
Ah bon. :-)
Quelqu'un a-t-il une meilleure solution ?
Pour Mark : le code explique-t-il mieux le problème ? La méthode Main devrait vous donner un aperçu.