Ejemplo n.º 1
0
        /// <summary>
        /// Create an instance of the requested <see cref="Type"/> using the constructor that best matches the specified parameters.
        /// </summary>
        /// <typeparam name="T">The interface <see cref="Type"/> of the instance to create.</typeparam>
        /// <param name="args">An array of arguments that match in number, order, and type the parameters of the constructor to invoke. If <paramref name="args"/>
        /// is an empty array or <c>null</c>, the constructor that takes no parameters (the default constructor) is invoked.</param>
        /// <returns>An instance of the requested <see cref="Type"/>.</returns>
        public static T Create <T>(params object[] args)
        {
            Type typeKey = typeof(T);
            Type typeVal = null;

            if (_localProviderValues.Value != null && _localProviderValues.Value.ContainsKey(typeKey.AssemblyQualifiedName))
            {
                return((T)_localProviderValues.Value[typeKey.AssemblyQualifiedName]);
            }

            if (_providerValues.ContainsKey(typeKey.AssemblyQualifiedName))
            {
                return((T)_providerValues[typeKey.AssemblyQualifiedName]);
            }

            if (_typeCache.ContainsKey(typeKey))
            {
                return((T)Activator.CreateInstance(_typeCache[typeKey], args));
            }

            if (!typeKey.GetTypeInfo().IsInterface)
            {
                throw new InvalidOperationException(string.Format("Factory can not create an instance of Type '{0}' as this is not an Interface.", typeKey.AssemblyQualifiedName));
            }

            if (_typeProviders.ContainsKey(typeKey.AssemblyQualifiedName))
            {
                typeVal = Type.GetType(_typeProviders[typeKey.AssemblyQualifiedName], false);
            }
            else
            {
                // Assume concrete is the same name with the leading "I" removed or itself if not following that naming convention; e.g. IFoo is Foo.
                string concreteName = SubstitutionRegex.Replace(typeKey.Name, string.Empty);

                // Look in same Assembly as Interface for implementation (primary).
                if (concreteName != typeKey.Name)
                {
                    typeVal = Type.GetType(MakeTypeName(typeKey, concreteName));
                }

                // Look at namespace substitutions as it may reside in another assembly (secondary).
                if (typeVal == null)
                {
                    foreach (var substitution in _substitutions.Where(x => x.Key == Substitution.CreateKey(typeKey)))
                    {
                        typeVal = Type.GetType(MakeTypeName(substitution.Concrete, SubstitutionRegex.Replace(typeKey.Name, string.Empty)));
                        if (typeVal != null)
                        {
                            break;
                        }
                    }
                }
            }

            if (typeVal == null)
            {
                throw new InvalidOperationException(string.Format("Factory can not create an instance of Type '{0}'; please check the naming convention and substitution rules.", typeKey.AssemblyQualifiedName));
            }

            lock (_lock)
            {
                if (_typeCache.ContainsKey(typeKey))
                {
                    return((T)Activator.CreateInstance(_typeCache[typeKey], args));
                }

                _typeCache.Add(typeKey, typeVal);
                return((T)Activator.CreateInstance(typeVal, args));
            }
        }