J'ai un cas similaire liées à l' "cher à créer et pourrait être utilisé", où, dans ma propre Cio mise en œuvre, je suis en ajoutant automagic de soutien pour des services usine.
En gros, au lieu de ceci:
public SomeService(ICDBurner burner)
{
}
vous voulez faire cela:
public SomeService(IServiceFactory<ICDBurner> burnerFactory)
{
}
ICDBurner burner = burnerFactory.Create();
Cela a deux avantages:
- En coulisses, le conteneur de service qui a résolu votre service est également utilisé pour résoudre le brûleur, si et lorsque cela est demandé
- Cela réduit les préoccupations que j'ai vu avant dans ce genre de cas où la manière typique serait d'injecter le conteneur de service lui-même en tant que paramètre à votre service, ce qui revient à dire "Ce service nécessite d'autres services, mais je ne vais pas facilement vous dire quels sont ceux qui"
L'usine de l'objet est assez facile à faire, et résout beaucoup de problèmes.
Voici mon usine de classe:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using LVK.IoC.Interfaces;
using System.Diagnostics;
namespace LVK.IoC
{
/// <summary>
/// This class is used to implement <see cref="IServiceFactory{T}"/> for all
/// services automatically.
/// </summary>
[DebuggerDisplay("AutoServiceFactory (Type={typeof(T)}, Policy={Policy})")]
internal class AutoServiceFactory<T> : ServiceBase, IServiceFactory<T>
{
#region Private Fields
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
private readonly String _Policy;
#endregion
#region Construction & Destruction
/// <summary>
/// Initializes a new instance of the <see cref="AutoServiceFactory<T>"/> class.
/// </summary>
/// <param name="serviceContainer">The service container involved.</param>
/// <param name="policy">The policy to use when resolving the service.</param>
/// <exception cref="ArgumentNullException"><paramref name="serviceContainer"/> is <c>null</c>.</exception>
public AutoServiceFactory(IServiceContainer serviceContainer, String policy)
: base(serviceContainer)
{
_Policy = policy;
}
/// <summary>
/// Initializes a new instance of the <see cref="AutoServiceFactory<T>"/> class.
/// </summary>
/// <param name="serviceContainer">The service container involved.</param>
/// <exception cref="ArgumentNullException"><paramref name="serviceContainer"/> is <c>null</c>.</exception>
public AutoServiceFactory(IServiceContainer serviceContainer)
: this(serviceContainer, null)
{
// Do nothing here
}
#endregion
#region Public Properties
/// <summary>
/// Gets the policy that will be used when the service is resolved.
/// </summary>
public String Policy
{
get
{
return _Policy;
}
}
#endregion
#region IServiceFactory<T> Members
/// <summary>
/// Constructs a new service of the correct type and returns it.
/// </summary>
/// <returns>The created service.</returns>
public IService<T> Create()
{
return MyServiceContainer.Resolve<T>(_Policy);
}
#endregion
}
}
En gros, quand je créer le conteneur de service de mon conteneur de service générateur de classe, tous les enregistrements sont automatiquement donné un autre co-service, la mise en œuvre de IServiceFactory pour ce service, sauf si le programmeur a explicitement inscrites sur lui/elle-même pour ce service. Le service ci-dessus est ensuite utilisé, avec un paramètre spécifiant le politique (qui peut être nulle si les politiques ne sont pas utilisés).
Cela me permet de faire cela:
var builder = new ServiceContainerBuilder();
builder.Register<ISomeService>()
.From.ConcreteType<SomeService>();
using (var container = builder.Build())
{
using (var factory = container.Resolve<IServiceFactory<ISomeService>>())
{
using (var service = factory.Instance.Create())
{
service.Instance.DoSomethingAwesomeHere();
}
}
}
Bien sûr, un usage plus typique serait avec votre Graveur de CD de l'objet. Dans le code ci-dessus, je voudrais résoudre le service à la place, bien sûr, mais c'est une illustration de ce qui se passe.
Donc, avec votre graveur de cd du service à la place:
var builder = new ServiceContainerBuilder();
builder.Register<ICDBurner>()
.From.ConcreteType<CDBurner>();
builder.Register<ISomeService>()
.From.ConcreteType<SomeService>(); // constructor used in the top of answer
using (var container = builder.Build())
{
using (var service = container.Resolve<ISomeService>())
{
service.Instance.DoSomethingHere();
}
}
à l'intérieur du service, vous pouvez maintenant avoir un service, un service de l'usine, qui sait comment faire pour résoudre votre graveur de cd de services sur demande. Ceci est utile pour les raisons suivantes:
- Vous pourriez vouloir résoudre plus d'un service dans le même temps (de graver des deux disques en même temps?)
- Vous ne pourriez pas besoin de cela, il pourrait être coûteux à créer, de sorte que vous ne le résoudre si nécessaire
- Vous pourriez avoir besoin pour résoudre, d'en disposer, de les résoudre, d'en disposer, à plusieurs reprises, au lieu d'espérer/essayer de nettoyer un service existant instance
- Vous avez également le ralentissement de votre constructeur les services dont vous avez besoin , et ceux dont vous pourriez avoir besoin
Voici deux en même temps:
using (var service1 = container.Resolve<ISomeService>())
using (var service2 = container.Resolve<ISomeService>())
{
service1.Instance.DoSomethingHere();
service2.Instance.DoSomethingHere();
}
Voici deux les uns après les autres, ne pas réutiliser le même service:
using (var service = container.Resolve<ISomeService>())
{
service.Instance.DoSomethingHere();
}
using (var service = container.Resolve<ISomeService>())
{
service.Instance.DoSomethingElseHere();
}