コード例 #1
0
        IEnumerable <TypeVault> FindRegistrations(Type type, RequestCache cache)
        {
            if (cache != null)
            {
                var cvault = cache.GetVault(type);
                if (cvault != null)
                {
                    yield return(cvault);
                }
            }

            EnsureAlive();
            List <TypeVault> list;

            if (!reverseInheritance.TryGetValue(type, out list))
            {
                yield break;
            }
            foreach (var vault in list)
            {
                yield return(vault);
            }
        }
コード例 #2
0
        /// <summary>
        /// Resolve all registered service that inherit from, or implement or are <paramref name="type"/>.
        /// If none are registered, it will create and return newly create instance of <paramref name="type"/>
        /// , that will be saved in the <paramref name="cache"/>.
        /// </summary>
        /// <param name="type">The requested type</param>
        /// <param name="cache">Where newly create instance that are not service are cached for reuse.</param>
        /// <returns>Al registered service which implement or are subclass of <paramref name="type"/> or a newly create one.</returns>
        public IEnumerable <object> ResolveAll(Type type, RequestCache cache = null)
        {
            if (cache == null)
            {
                cache = new RequestCache();
            }
            var none = true;

            foreach (var vault in FindRegistrations(type, cache))
            {
                none = false;
                Resolve(vault, cache);
                yield return(vault.Instance);
            }
            if (none)
            {
                if (!CanCreate(type, cache))
                {
                    throw new InvalidOperationException($"Can't create {type.FullName}");
                }
                var instance = Create(type, cache);
                yield return(instance);
            }
        }
コード例 #3
0
        /// <summary>
        /// Create that object from scratch regardless of registration
        /// </summary>
        /// <param name="type">The type to instantiate.</param>
        /// <param name="cache">A cache of possible instance to use as property, constructor argument and the like, on top of registered services.</param>
        /// <returns>A newly created instance</returns>
        /// <exception cref="InvalidOperationException">If no appropriate constructor can be found.</exception>
        public object Create(Type type, RequestCache cache = null)
        {
            bool first = createSession == null;

            if (first)
            {
                createSession = new List <IRegistryDelegate>();
            }
            if (cache == null)
            {
                cache = new RequestCache();
            }
            try
            {
                var ctors = FindConstructors(type, cache);
                var qc    = (
                    from c in ctors
                    where c.IsPublic // private constructor are private for a reason, don't use them!
                    let ppp = c.GetParameters()
                              orderby c.IsPublic descending, ppp.Length descending
                    select new { c, ppp }
                    )
                            .FirstOrDefault();
                if (qc == null)
                {
                    throw new InvalidOperationException($"Type {type.FullName} can't be Activated, no constructor can be called at this time.");
                }

                var cargs = new object[qc.ppp.Length];
                for (int i = 0; i < qc.ppp.Length; i++)
                {
                    var p     = qc.ppp[i];
                    var impa  = p.GetCustomAttribute <ImportAttribute>();
                    var t     = (impa != null ? impa.ImportedType : null) ?? p.ParameterType;
                    var vault = FindRegistrations(t, cache).FirstOrDefault(x => x.Instance != null || x.Type != type);
                    if (vault != null)
                    {
                        Resolve(vault, cache);
                        cargs[i] = vault.Instance;
                    }
                    else if (p.HasDefaultValue)
                    {
                        cargs[i] = p.DefaultValue;
                    }
                    else
                    {
                        var instance = Create(p.ParameterType, cache);
                        cargs[i] = instance;
                    }
                }
                var fc     = FastMethod.GetMethod(qc.c);
                var result = fc.Invoke(null, cargs);
                cache[type] = result;
                if (result is IRegistryDelegate)
                {
                    createSession.Add((IRegistryDelegate)result);
                }
                ResolveProperties(result, cache);
                return(result);
            }
            finally
            {
                if (first)
                {
                    ForEach(createSession, x => x.OnRegistryCreated());
                    createSession = null;
                }
            }
        }
コード例 #4
0
 /// <summary>
 /// Create that object from scratch regardless of registration
 /// </summary>
 /// <typeparam name="T">The type to instantiate.</typeparam>
 /// <param name="cache">A cache of possible instance to use as property, constructor argument and the like, on top of registered services.</param>
 /// <returns>A newly created instance</returns>
 /// <exception cref="InvalidOperationException">If no appropriate constructor can be found.</exception>
 public T Create <T>(RequestCache cache = null)
 {
     return((T)Create(typeof(T), cache));
 }
コード例 #5
0
 /// <summary>
 /// Whether given type can be created. Basically it must be a concrete class with some constructors
 /// with arguments that can also be created (or resolved).
 /// </summary>
 /// <param name="type">The type to check for creation.</param>
 /// <param name="cache">A cache of instance to possibly use for construction.</param>
 /// <returns>Whether the type can be instantiated</returns>
 public bool CanCreate(Type type, RequestCache cache = null)
 {
     return(FindConstructors(type, cache).Any());
 }
コード例 #6
0
 /// <summary>
 /// Whether given type can be created. Basically it must be a concrete class with some constructors
 /// with arguments that can also be created (or resolved).
 /// </summary>
 /// <typeparam name="T">The type to check for creation.</typeparam>
 /// <param name="cache">A cache of instance to possibly use for construction.</param>
 /// <returns>Whether the type can be instantiated</returns>
 public bool CanCreate <T>(RequestCache cache = null)
 {
     return(CanCreate(typeof(T), cache));
 }
コード例 #7
0
        /// <summary>
        /// Will set all properties marked with <see cref="ImportAttribute"/>. If property is an array or a <see cref="List{T}"/>
        /// It will <see cref="ResolveAll(Type, RequestCache)"/> and set up the array / collection with the result.
        /// </summary>
        /// <param name="instance">The object which property must be resolved.</param>
        /// <param name="cache">A cache for the request so that each instance which are not service is created only once.</param>
        public void ResolveProperties(object instance, RequestCache cache = null)
        {
            if (instance == null)
            {
                throw new ArgumentNullException(nameof(instance));
            }
            if (cache == null)
            {
                cache = new RequestCache();
            }

            var ftype = FastType.GetType(instance.GetType());
            var props = (
                from p in ftype.GetRuntimeMembers()
                where !p.IsStatic
                let pi = p.Member.GetCustomAttributes <ImportAttribute>().FirstOrDefault()
                         where pi != null
                         select new { p, pi }
                ).ToList();

            foreach (var item in props)
            {
                var p  = item.p;
                var pi = item.pi;
                if (IsBaseClass(typeof(IEnumerable), p.Type.Type))
                {
                    var t = pi.ImportedType;
                    // T[]
                    if (p.Type.Type.IsArray)
                    {
                        if (t == null)
                        {
                            t = p.Type.Type.GetElementType();
                        }
                        if (!IsBaseClass(p.Type.Type.GetElementType(), t))
                        {
                            throw new NotSupportedException($"Property {instance.GetType().Name}.{p.Name}, can't import {t.Name}");
                        }
                        var objs = FindRegistrations(t, cache).Select(x => Resolve(x, cache)).ToList();
                        var prop = Array.CreateInstance(t, objs.Count);
                        for (int i = 0; i < objs.Count; i++)
                        {
                            prop.SetValue(objs[i], i);
                        }
                        item.p.SetValue(instance, prop);
                    }
                    // List<T>
                    else
                    {
                        if (!IsBaseClass(typeof(IList), p.Type.Type))
                        {
                            throw new InvalidOperationException($"[Import] property {instance.GetType().Name}.{p.Name} must be an array or an IList");
                        }

                        if (t == null)
                        {
                            var ga = p.Type.Type.GenericTypeArguments;
                            if (ga.Length != 1)
                            {
                                throw new NotSupportedException($"[Import] property {instance.GetType().Name}.{p.Name} must be generic or the Import type must be defined");
                            }
                            t = ga[0];
                        }
                        var value = p.GetValue(instance);
                        if (value == null)
                        {
                            if (!CanBeInstantiated(p.Type.Type) || !p.CanSet)
                            {
                                throw new InvalidOperationException($"Can't [Import]{p.Type.Type.Name} for {instance.GetType().Name}.{p.Name}");
                            }
                            value = Create(p.Type.Type, cache);
                            p.SetValue(instance, value);
                        }
                        var list = (IList)value;
                        ForEach(FindRegistrations(t, cache).Select(x => Resolve(x, cache)), x => list.Add(x));
                    }
                }
                else
                {
                    // simple property
                    var o = ResolveAll(pi.ImportedType ?? p.Type.Type, cache).First();
                    item.p.SetValue(instance, o);
                }
            }
        }
コード例 #8
0
 /// <summary>
 /// Resolve all registered service that inherit from, or implement or are <typeparamref name="T"/>.
 /// If none are registered, it will create and return newly create instance of <typeparamref name="T"/>
 /// , that will be saved in the <paramref name="cache"/>.
 /// </summary>
 /// <typeparam name="T">The requested type</typeparam>
 /// <param name="cache">Where newly create instance that are not service are cached for reuse.</param>
 /// <returns>Al registered service which implement or are subclass of <typeparamref name="T"/> or a newly create one.</returns>
 public IEnumerable <T> ResolveAll <T>(RequestCache cache = null)
 {
     return(ResolveAll(typeof(T), cache).Cast <T>());
 }
コード例 #9
0
 /// <summary>
 /// This will resolve the first <paramref name="type"/> with <see cref="ResolveAll(Type, RequestCache)"/>
 /// </summary>
 /// <param name="type">The requested type</param>
 /// <param name="cache">A cache for all instance that need be create and are not a registered service. Can be null</param>
 /// <returns>An instance of type <paramref name="type"/>, either a reused service if registered, or newly created instance otherwise.</returns>
 public object Resolve(Type type, RequestCache cache = null)
 {
     return(ResolveAll(type, cache).First());
 }
コード例 #10
0
 /// <summary>
 /// This will resolve the first <typeparamref name="T"/> with <see cref="ResolveAll(Type, RequestCache)"/>
 /// </summary>
 /// <typeparam name="T">The requested type</typeparam>
 /// <param name="cache">A cache for all instance that need be create and are not a registered service. Can be null</param>
 /// <returns>An instance of <typeparamref name="T"/>, either a reused service if registered, or newly created instance otherwise.</returns>
 public T Resolve <T>(RequestCache cache = null)
 {
     return((T)ResolveAll(typeof(T), (RequestCache)null).First());
 }