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; }
/// <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; }
/// <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; } }
/// <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(); } }
/// <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); } } } } }
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); }