Пфех, я нашел ответ. Наверное, не самый лучший, но хоть что-то для начала.
Посмотрите на следующий полный пример: (для этого я использовал NInject):
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);
}
}
}
Когда он запущен, он отображает:
Constructor for B called!
Constructor for C called!
Сначала я должен был вручную внедрить уже созданные объекты x1 и x2 в ядро. Get-вызовы. Похоже, этого было достаточно, чтобы NInject разрешил правильную сущность, но как только я добавил вторую привязку для IA, он пожаловался на множественные привязки по умолчанию для IA. Поэтому мне пришлось сделать некоторую контекстную привязку:
Bind<IA>().To<B>().Only(When.Context.Parameter<ConstructorArgumentParameter>("x").Matches(
e =>
{
return e.Value.GetType().Equals(typeof(Y));
}));
Проверяет, имеет ли параметр x тип Y. Если да, используется эта привязка.
Опять же, хотя это решение, оно, вероятно, далеко не оптимально. Я хотел, чтобы NInject мог разрешить правильный тип (B или C) для создания экземпляра из динамического типа (Y или Z) параметра (x).
Ах, хорошо. : -)
У кого-нибудь есть лучшее решение?
To Mark: код лучше объясняет проблему? Основной метод должен дать вам обзор.