Files
Umbraco-CMS/src/Umbraco.Core/DependencyInjection/CollectionBuilderBase.cs

106 lines
3.6 KiB
C#
Raw Normal View History

2016-08-16 10:00:14 +02:00
using System;
using System.Collections.Generic;
using System.Linq;
using LightInject;
namespace Umbraco.Core.DependencyInjection
{
/// <summary>
2016-08-16 10:25:19 +02:00
/// Provides a base class for collection builders.
2016-08-16 10:00:14 +02:00
/// </summary>
/// <typeparam name="TCollection">The type of the collection.</typeparam>
/// <typeparam name="TItem">The type of the items.</typeparam>
2016-08-16 10:25:19 +02:00
public abstract class CollectionBuilderBase<TCollection, TItem> : ICollectionBuilder<TCollection, TItem>
where TCollection : IBuilderCollection<TItem>
2016-08-16 10:00:14 +02:00
{
private readonly IServiceContainer _container;
private readonly List<Type> _types = new List<Type>();
private readonly object _locker = new object();
private bool _typesRegistered;
/// <summary>
2016-08-16 10:25:19 +02:00
/// Initializes a new instance of the <see cref="CollectionBuilderBase{TCollection,TItem}"/>
2016-08-16 10:00:14 +02:00
/// class with a service container.
/// </summary>
/// <param name="container">A service container.</param>
2016-08-16 10:25:19 +02:00
protected CollectionBuilderBase(IServiceContainer container)
2016-08-16 10:00:14 +02:00
{
_container = container;
}
2016-08-16 10:25:19 +02:00
/// <summary>
/// Configures the internal list of types.
/// </summary>
/// <param name="action">The action to execute.</param>
/// <remarks>Throws if the types have already been registered.</remarks>
protected void Configure(Action<List<Type>> action)
2016-08-16 10:00:14 +02:00
{
lock (_locker)
{
if (_typesRegistered) throw new InvalidOperationException();
2016-08-16 10:25:19 +02:00
action(_types);
2016-08-16 10:00:14 +02:00
}
}
2016-08-16 10:25:19 +02:00
/// <summary>
/// Gets the types.
/// </summary>
/// <param name="types">The internal list of types.</param>
/// <returns>The list of types to register.</returns>
protected virtual IEnumerable<Type> GetTypes(IEnumerable<Type> types)
2016-08-16 10:00:14 +02:00
{
return types;
}
private void RegisterTypes()
{
lock (_locker)
{
if (_typesRegistered) return;
var prefix = GetType().FullName + "_";
var i = 0;
2016-08-16 10:25:19 +02:00
foreach (var type in GetTypes(_types))
2016-08-16 10:00:14 +02:00
{
var name = $"{prefix}{i++:00000}";
_container.Register(typeof(TItem), type, name);
}
_typesRegistered = true;
}
}
/// <summary>
/// Gets a collection.
/// </summary>
/// <returns>A collection.</returns>
/// <remarks>
/// <para>Creates a new collection each time it is invoked, but only registers types once.</para>
/// <para>Explicitely implemented in order to hide it to users.</para>
/// </remarks>
2016-08-16 10:25:19 +02:00
TCollection ICollectionBuilder<TCollection, TItem>.GetCollection()
2016-08-16 10:00:14 +02:00
{
RegisterTypes(); // will do it only once
var prefix = GetType().FullName + "_";
// fixme - shouldn't we save this somewhere?
var services = _container.AvailableServices
.Where(x => x.ServiceName.StartsWith(prefix))
.OrderBy(x => x.ServiceName);
var items = services
.Select(x => _container.GetInstance<TItem>(x.ServiceName))
.ToArray();
return CreateCollection(items);
}
/// <summary>
/// Creates the injected collection.
/// </summary>
/// <param name="items">The items.</param>
/// <returns>An injected collection containing the items.</returns>
protected abstract TCollection CreateCollection(IEnumerable<TItem> items);
}
}