Przykład zależności pomiędzy obiektami:
public class AudiA4 { private readonly IEngine _engine; public AudiA4(IEngine engine) { _engine = engine; } public void Run() { _engine.Run(); } } public interface IEngine { void Run(); } public class DieselEngine : IEngine { public void Run() { Console.Write("Diesel engine running..."); } }
Kontener tworzą dwie metody. Pierwsza pozwala na rejestrowanie typów w słowniku. Typy rejestrowane powinny być po interfejsach tylko wtedy jeżeli implementujemy dany interfejs więcej niż raz. W przeciwnym wypadku tworzymy niepotrzebne byty. Druga metoda tworzy obiekt na podstawie wcześniej skonfigurowanych zależności. W C# możemy skorzystać z mechanizmu Reflection, przez co zajmuje nam to bardzo mało kodu. Ponieważ w bardziej rozbudowany aplikacjach możemy mieć wielopoziomowe grafy obiektów, metodę Resolve wołamy rekurencyjnie, aby rozwiązać wszystkie zależności.
public class IocContainer { private Dictionary<Type, Type> dependencyMap; public IocContainer() { dependencyMap = new Dictionary<Type, Type>(); } public T Resolve<T>() { return (T) Resolve(typeof(T)); } private object Resolve(Type type) { Type resolvedType = null; try { resolvedType = dependencyMap[type]; } catch { throw new KeyNotFoundException(String.Format("Cannot resolve type {0}", type.FullName)); } var ctor = resolvedType.GetConstructors().First(); var parameters = ctor.GetParameters(); if (parameters.Count() == 0) return Activator.CreateInstance(resolvedType); IList<object> @params = new List<object>(); foreach (var parameter in parameters) { @params.Add(Resolve(parameter.ParameterType)); } return ctor.Invoke(@params.ToArray()); } public void Register<TFrom, TTo>() { dependencyMap.Add(typeof(TFrom), typeof(TTo)); } }
Przykład użycia kontenera:
static void Main(string[] args) { var container = new IocContainer(); container.Register<AudiA4, AudiA4>(); //zależnie od konfiguracji container.Register<IEngine, DieselEngine>(); var car = container.Resolve<AudiA4>(); car.Run(); }
Brak komentarzy:
Prześlij komentarz