J'écris toujours un wrapper d'adaptateur pour tout conteneur IoC, qui ressemble à ceci:
public static class Ioc
{
public static IIocContainer Container { get; set; }
}
public interface IIocContainer
{
object Get(Type type);
T Get<T>();
T Get<T>(string name, string value);
void Inject(object item);
T TryGet<T>();
}
Pour Ninject, en particulier, la classe Adapter concrète ressemble à ceci:
public class NinjectIocContainer : IIocContainer
{
public readonly IKernel Kernel;
public NinjectIocContainer(params INinjectModule[] modules)
{
Kernel = new StandardKernel(modules);
new AutoWirePropertyHeuristic(Kernel);
}
private NinjectIocContainer()
{
Kernel = new StandardKernel();
Kernel.Load(AppDomain.CurrentDomain.GetAssemblies());
new AutoWirePropertyHeuristic(Kernel);
}
public object Get(Type type)
{
try
{
return Kernel.Get(type);
}
catch (ActivationException exception)
{
throw new TypeNotResolvedException(exception);
}
}
public T TryGet<T>()
{
return Kernel.TryGet<T>();
}
public T Get<T>()
{
try
{
return Kernel.Get<T>();
}
catch (ActivationException exception)
{
throw new TypeNotResolvedException(exception);
}
}
public T Get<T>(string name, string value)
{
var result = Kernel.TryGet<T>(metadata => metadata.Has(name) &&
(string.Equals(metadata.Get<string>(name), value,
StringComparison.InvariantCultureIgnoreCase)));
if (Equals(result, default(T))) throw new TypeNotResolvedException(null);
return result;
}
public void Inject(object item)
{
Kernel.Inject(item);
}
}
La principale raison pour cela est d'abstraire le cadre IoC, donc je peux le remplacer à tout moment - étant donné que la différence entre les cadres est généralement dans la configuration plutôt que dans l'utilisation.
Mais, en prime, les choses deviennent également beaucoup plus faciles pour l'utilisation du cadre IoC dans d'autres cadres qui ne le supportent pas de manière inhérente. Pour WinForms, par exemple, il s'agit de deux étapes:
Dans votre méthode Main, instanciez simplement un conteneur avant de faire autre chose.
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
try
{
Ioc.Container = new NinjectIocContainer( /* include modules here */ );
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new MyStartupForm());
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
}
}
Et puis avoir une forme de base, dont dérivent d'autres formes, qui appelle Injecter sur elle-même.
public IocForm : Form
{
public IocForm() : base()
{
Ioc.Container.Inject(this);
}
}
Cela indique à l'heuristique de câblage automatique de tenter d'injecter récursivement toutes les propriétés du formulaire qui correspondent aux règles définies dans vos modules.