예제 #1
0
        private object GetInstanceImpl(Type serviceType, string key, bool onlyShared = false)
        {
            lock (_registry)
            {
                // Try to locate matching service entry in the current or a parent container.
                ServiceRegistration registration = new ServiceRegistration(serviceType, key);
                ServiceEntry entry;
                ServiceContainer container;

                if (_registry.TryGetValue(registration, out entry))
                {
                    // Service entry found in local registry.
                    container = this;
                }
                else
                {
                    // Check parent containers.
                    container = _parent;
                    while (container != null)
                    {
                        lock (container._registry)
                        {
                            if (container._registry.TryGetValue(registration, out entry))
                                break;
                        }

                        container = container._parent;
                    }
                }

                if (entry != null)
                {
                    // Resolve instance from service entry.
                    if (entry.CreationPolicy == CreationPolicy.NonShared)
                    {
                        if (onlyShared)
                            return null;

                        // Create non-shared (transient) service instance.
                        var instance = entry.CreateInstance(this);

                        // Track for disposal, if necessary.
                        StoreInstance(entry, instance);

                        return instance;
                    }

                    if (entry.CreationPolicy == CreationPolicy.LocalShared && container != this)
                    {
                        // Service entry was found in a parent container, but the service is 
                        // configured to be created per container. --> Copy into local registry.
                        entry = new ServiceEntry(entry);
                        _registry.Add(registration, entry);
                        container = this;
                    }

                    // Create shared service instance, if not already cached.
                    // (Double-check to avoid unnecessary lock.)
                    if (entry.Instances == null)
                    {
                        lock (entry)
                        {
                            if (entry.Instances == null)
                            {
                                var instance = entry.CreateInstance(container);
                                StoreInstance(entry, instance);
                            }
                        }
                    }

                    return entry.Instances;
                }
            }

            // The requested service type is not directly registered. 

            // Other supported types are:  
            // - IEnumerable<TService> ... service instance collection
            // - Func<TService> .......... factory method for lazy resolution

#if !NETFX_CORE && !NET45
            if (serviceType.IsGenericType)
#else
            if (serviceType.GetTypeInfo().IsGenericType)
#endif
            {
                var genericType = serviceType.GetGenericTypeDefinition();
                if (genericType == typeof(IEnumerable<>))
                {
                    // Requested type is IEnumerable<TService>.

                    // Get typeof(TService).
#if !NETFX_CORE && !NET45
                    Type actualServiceType = serviceType.GetGenericArguments()[0];
#else
                    Type actualServiceType = serviceType.GetTypeInfo().GenericTypeArguments[0];
#endif

                    // Get array of all named TService instances.
                    object[] instances = GetAllInstancesImpl(actualServiceType).ToArray();

                    // Create and fill TService[] array.
                    Array array = Array.CreateInstance(actualServiceType, instances.Length);
                    for (int i = 0; i < array.Length; i++)
                        array.SetValue(instances[i], i);

                    return array;
                }

                if (genericType == typeof(Func<>))
                {
                    // Requested type is Func<TService>.
#if !NETFX_CORE && !NET45
                    var actualServiceType = serviceType.GetGenericArguments()[0];
                    var factoryFactoryType = typeof(ServiceFactoryFactory<>).MakeGenericType(actualServiceType);
                    var factoryFactoryInstance = Activator.CreateInstance(factoryFactoryType);
                    var factoryFactoryMethod = factoryFactoryType.GetMethod("Create");
#else
                    var actualServiceType = serviceType.GetTypeInfo().GenericTypeArguments[0];
                    var factoryFactoryType = typeof(ServiceFactoryFactory<>).MakeGenericType(actualServiceType);
                    var factoryFactoryInstance = Activator.CreateInstance(factoryFactoryType);
                    var factoryFactoryMethod = factoryFactoryType.GetTypeInfo().GetDeclaredMethod("Create");
#endif
                    return factoryFactoryMethod.Invoke(factoryFactoryInstance, new object[] { this, key });
                }

                //if (genericType == typeof(Func<,>) && serviceType.GetGenericArguments()[0] == typeof(string))
                //{
                //  // Requested type is Func<string, TService> where the argument is the name of the service.
                //  ...
                //}
            }

            return null;
        }
예제 #2
0
 /// <summary>
 /// Initializes a new instance of the <see cref="ServiceEntry"/> class by copying the settings
 /// of an existing service entry.
 /// </summary>
 /// <param name="entry">The <see cref="ServiceEntry"/> from which to copy the settings.</param>
 public ServiceEntry(ServiceEntry entry)
 {
     CreateInstance = entry.CreateInstance;
     CreationPolicy = entry.CreationPolicy;
     DisposalPolicy = entry.DisposalPolicy;
 }
예제 #3
0
        /// <overloads>
        /// <summary>
        /// Registers a service.
        /// </summary>
        /// </overloads>
        /// 
        /// <summary>
        /// Registers a service using a custom factory method and certain creation and disposal
        /// policies.
        /// </summary>
        /// <param name="serviceType">The type of the service.</param>
        /// <param name="key">
        /// The name under which the object should be registered. Can be <see langword="null"/> or
        /// empty.
        /// </param>
        /// <param name="createInstance">
        /// The factory method responsible for serving the requests from the container.
        /// </param>
        /// <param name="creationPolicy">
        /// The creation policy that specifies when and how a service will be instantiated.
        /// </param>
        /// <param name="disposalPolicy">
        /// The disposal policy that specifies when a service instance will be disposed. (Only
        /// relevant if the service instance implements <see cref="IDisposable"/>.)
        /// </param>
        /// <remarks>
        /// If a service with the same type and name is already registered, the existing entry will
        /// be replaced.
        /// </remarks>
        /// <exception cref="ArgumentNullException">
        /// <paramref name="serviceType"/> or <paramref name="createInstance"/> is
        /// <see langword="null"/>.
        /// </exception>
        public void Register(Type serviceType, string key, Func<ServiceContainer, object> createInstance, CreationPolicy creationPolicy, DisposalPolicy disposalPolicy)
        {
            ThrowIfDisposed();

            if (serviceType == null)
                throw new ArgumentNullException(nameof(serviceType));
            if (createInstance == null)
                throw new ArgumentNullException(nameof(createInstance));

            var registration = new ServiceRegistration(serviceType, key);
            var entry = new ServiceEntry(createInstance, creationPolicy, disposalPolicy);
            lock (_registry)
            {
                _registry[registration] = entry;
            }
        }
예제 #4
0
        /// <summary>
        /// Disposes of objects whose lifetime is controlled by the service container.
        /// </summary>
        /// <param name="entry">The service entry in the registry.</param>
        private static void DisposeInstances(ServiceEntry entry)
        {
            if (entry.DisposalPolicy != DisposalPolicy.Automatic)
                return;

            if (entry.Instances is IDisposable)
            {
                // Shared disposable instance.
                Debug.Assert(entry.CreationPolicy == CreationPolicy.Shared || entry.CreationPolicy == CreationPolicy.LocalShared);
                var instance = (IDisposable)entry.Instances;
                instance.Dispose();
            }
            else if (entry.Instances is WeakReference)
            {
                // Single non-shared disposable instance.
                Debug.Assert(entry.CreationPolicy == CreationPolicy.NonShared);
                var instance = ((WeakReference)entry.Instances).Target;
                instance.SafeDispose();
            }
            else if (entry.Instances is WeakCollection<IDisposable>)
            {
                //  Multiple non-shared disposable instance.
                Debug.Assert(entry.CreationPolicy == CreationPolicy.NonShared);
                var instances = (WeakCollection<IDisposable>)entry.Instances;
                foreach (var instance in instances)
                    instance.Dispose();
            }
        }
예제 #5
0
        /// <summary>
        /// Stores the shared service instance, or keeps track of disposable instances for automatic
        /// disposal.
        /// </summary>
        /// <param name="entry">The service entry in the registry.</param>
        /// <param name="instance">The service instance. (Can be <see langword="null"/>.)</param>
        private static void StoreInstance(ServiceEntry entry, object instance)
        {
            if (instance == null)
                return;

            if (entry.CreationPolicy == CreationPolicy.Shared || entry.CreationPolicy == CreationPolicy.LocalShared)
            {
                // Store shared instance.
                Debug.Assert(entry.Instances == null);
                entry.Instances = instance;
            }
            else
            {
                // Keep track of non-shared instance for automatic disposal.
                Debug.Assert(entry.CreationPolicy == CreationPolicy.NonShared);
                if (entry.DisposalPolicy == DisposalPolicy.Automatic)
                {
                    var disposable = instance as IDisposable;
                    if (disposable != null)
                    {
                        if (entry.Instances == null)
                        {
                            // This the first service instance.
                            entry.Instances = new WeakReference(disposable);
                        }
                        else if (entry.Instances is WeakReference)
                        {
                            // This is the second service instance.
                            var weakReference = (WeakReference)entry.Instances;
                            var previousDisposable = (IDisposable)weakReference.Target;
                            if (previousDisposable == null)
                            {
                                // First service instance has already been garbage collected.
                                weakReference.Target = instance;
                            }
                            else
                            {
                                // First service instance is still alive.
                                entry.Instances = new WeakCollection<IDisposable>
                                {
                                    previousDisposable,
                                    disposable
                                };
                            }
                        }
                        else if (entry.Instances is WeakCollection<IDisposable>)
                        {
                            // Multiple service instance.
                            var weakCollection = (WeakCollection<IDisposable>)entry.Instances;
                            weakCollection.Add(disposable);
                        }
                    }
                }
            }
        }
예제 #6
0
 /// <summary>
 /// Initializes a new instance of the <see cref="ServiceEntry"/> class by copying the settings
 /// of an existing service entry.
 /// </summary>
 /// <param name="entry">The <see cref="ServiceEntry"/> from which to copy the settings.</param>
 public ServiceEntry(ServiceEntry entry)
 {
     CreateInstance = entry.CreateInstance;
     CreationPolicy = entry.CreationPolicy;
     DisposalPolicy = entry.DisposalPolicy;
 }
예제 #7
0
        private object GetInstanceImpl(Type serviceType, string key, bool onlyShared = false)
        {
            lock (_registry)
            {
                // Try to locate matching service entry in the current or a parent container.
                ServiceRegistration registration = new ServiceRegistration(serviceType, key);
                ServiceEntry        entry;
                ServiceContainer    container;

                if (_registry.TryGetValue(registration, out entry))
                {
                    // Service entry found in local registry.
                    container = this;
                }
                else
                {
                    // Check parent containers.
                    container = _parent;
                    while (container != null)
                    {
                        lock (container._registry)
                        {
                            if (container._registry.TryGetValue(registration, out entry))
                            {
                                break;
                            }
                        }

                        container = container._parent;
                    }
                }

                if (entry != null)
                {
                    // Resolve instance from service entry.
                    if (entry.CreationPolicy == CreationPolicy.NonShared)
                    {
                        if (onlyShared)
                        {
                            return(null);
                        }

                        // Create non-shared (transient) service instance.
                        var instance = entry.CreateInstance(this);

                        // Track for disposal, if necessary.
                        StoreInstance(entry, instance);

                        return(instance);
                    }

                    if (entry.CreationPolicy == CreationPolicy.LocalShared && container != this)
                    {
                        // Service entry was found in a parent container, but the service is
                        // configured to be created per container. --> Copy into local registry.
                        entry = new ServiceEntry(entry);
                        _registry.Add(registration, entry);
                        container = this;
                    }

                    // Create shared service instance, if not already cached.
                    // (Double-check to avoid unnecessary lock.)
                    if (entry.Instances == null)
                    {
                        lock (entry)
                        {
                            if (entry.Instances == null)
                            {
                                var instance = entry.CreateInstance(container);
                                StoreInstance(entry, instance);
                            }
                        }
                    }

                    return(entry.Instances);
                }
            }

            // The requested service type is not directly registered.

            // Other supported types are:
            // - IEnumerable<TService> ... service instance collection
            // - Func<TService> .......... factory method for lazy resolution

#if !NETFX_CORE && !NET45
            if (serviceType.IsGenericType)
#else
            if (serviceType.GetTypeInfo().IsGenericType)
#endif
            {
                var genericType = serviceType.GetGenericTypeDefinition();
                if (genericType == typeof(IEnumerable <>))
                {
                    // Requested type is IEnumerable<TService>.

                    // Get typeof(TService).
#if !NETFX_CORE && !NET45
                    Type actualServiceType = serviceType.GetGenericArguments()[0];
#else
                    Type actualServiceType = serviceType.GetTypeInfo().GenericTypeArguments[0];
#endif

                    // Get array of all named TService instances.
                    object[] instances = GetAllInstancesImpl(actualServiceType).ToArray();

                    // Create and fill TService[] array.
                    Array array = Array.CreateInstance(actualServiceType, instances.Length);
                    for (int i = 0; i < array.Length; i++)
                    {
                        array.SetValue(instances[i], i);
                    }

                    return(array);
                }

                if (genericType == typeof(Func <>))
                {
                    // Requested type is Func<TService>.
#if !NETFX_CORE && !NET45
                    var actualServiceType      = serviceType.GetGenericArguments()[0];
                    var factoryFactoryType     = typeof(ServiceFactoryFactory <>).MakeGenericType(actualServiceType);
                    var factoryFactoryInstance = Activator.CreateInstance(factoryFactoryType);
                    var factoryFactoryMethod   = factoryFactoryType.GetMethod("Create");
#else
                    var actualServiceType      = serviceType.GetTypeInfo().GenericTypeArguments[0];
                    var factoryFactoryType     = typeof(ServiceFactoryFactory <>).MakeGenericType(actualServiceType);
                    var factoryFactoryInstance = Activator.CreateInstance(factoryFactoryType);
                    var factoryFactoryMethod   = factoryFactoryType.GetTypeInfo().GetDeclaredMethod("Create");
#endif
                    return(factoryFactoryMethod.Invoke(factoryFactoryInstance, new object[] { this, key }));
                }

                //if (genericType == typeof(Func<,>) && serviceType.GetGenericArguments()[0] == typeof(string))
                //{
                //  // Requested type is Func<string, TService> where the argument is the name of the service.
                //  ...
                //}
            }

            return(null);
        }