using System; using System.Collections.Generic; using System.Linq; using ModestTree; using ModestTree.Util; namespace Zenject { public abstract class KeyedFactoryBase : IValidatable { [Inject] readonly DiContainer _container = null; [InjectOptional] readonly List> _typePairs = null; Dictionary _typeMap = null; [InjectOptional] readonly Type _fallbackType = null; protected DiContainer Container { get { return _container; } } protected abstract IEnumerable ProvidedTypes { get; } public ICollection Keys { get { return _typeMap.Keys; } } protected Dictionary TypeMap { get { return _typeMap; } } [Inject] public void Initialize() { Assert.That(_fallbackType == null || _fallbackType.DerivesFromOrEqual(), "Expected fallback type '{0}' to derive from '{1}'", _fallbackType, typeof(TBase)); #if UNITY_EDITOR var duplicates = _typePairs.Select(x => x.First).GetDuplicates(); if (!duplicates.IsEmpty()) { throw Assert.CreateException( "Found duplicate values in KeyedFactory: {0}", duplicates.Select(x => x.ToString()).Join(", ")); } #endif _typeMap = _typePairs.ToDictionary(x => x.First, x => x.Second); _typePairs.Clear(); } public bool HasKey(TKey key) { return _typeMap.ContainsKey(key); } protected Type GetTypeForKey(TKey key) { Type keyedType; if (!_typeMap.TryGetValue(key, out keyedType)) { Assert.IsNotNull(_fallbackType, "Could not find instance for key '{0}'", key); return _fallbackType; } return keyedType; } public virtual void Validate() { foreach (var constructType in _typeMap.Values) { Container.InstantiateExplicit( constructType, ValidationUtil.CreateDefaultArgs(ProvidedTypes.ToArray())); } } protected static ConditionCopyNonLazyBinder AddBindingInternal(DiContainer container, TKey key) where TDerived : TBase { return container.Bind>() .FromInstance(ValuePair.New(key, typeof(TDerived))); } } // Zero parameters public class KeyedFactory : KeyedFactoryBase { protected override IEnumerable ProvidedTypes { get { return new Type[0]; } } public virtual TBase Create(TKey key) { var type = GetTypeForKey(key); return (TBase)Container.Instantiate(type); } } // One parameter public class KeyedFactory : KeyedFactoryBase { protected override IEnumerable ProvidedTypes { get { return new[] { typeof(TParam1) }; } } public virtual TBase Create(TKey key, TParam1 param1) { return (TBase)Container.InstantiateExplicit( GetTypeForKey(key), new List { InjectUtil.CreateTypePair(param1) }); } } // Two parameters public class KeyedFactory : KeyedFactoryBase { protected override IEnumerable ProvidedTypes { get { return new[] { typeof(TParam1), typeof(TParam2) }; } } public virtual TBase Create(TKey key, TParam1 param1, TParam2 param2) { return (TBase)Container.InstantiateExplicit( GetTypeForKey(key), new List { InjectUtil.CreateTypePair(param1), InjectUtil.CreateTypePair(param2) }); } } // Three parameters public class KeyedFactory : KeyedFactoryBase { protected override IEnumerable ProvidedTypes { get { return new[] { typeof(TParam1), typeof(TParam2), typeof(TParam3) }; } } public virtual TBase Create(TKey key, TParam1 param1, TParam2 param2, TParam3 param3) { return (TBase)Container.InstantiateExplicit( GetTypeForKey(key), new List { InjectUtil.CreateTypePair(param1), InjectUtil.CreateTypePair(param2), InjectUtil.CreateTypePair(param3) }); } } // Four parameters public class KeyedFactory : KeyedFactoryBase { protected override IEnumerable ProvidedTypes { get { return new[] { typeof(TParam1), typeof(TParam2), typeof(TParam3), typeof(TParam4) }; } } public virtual TBase Create(TKey key, TParam1 param1, TParam2 param2, TParam3 param3, TParam4 param4) { return (TBase)Container.InstantiateExplicit( GetTypeForKey(key), new List { InjectUtil.CreateTypePair(param1), InjectUtil.CreateTypePair(param2), InjectUtil.CreateTypePair(param3), InjectUtil.CreateTypePair(param4) }); } } }