Simple Injector Inject IEnumerable >

c# dependency-injection expression-trees simple-injector

Question

Comment puis-je injecter IEnumerable<Func<T>> utilisant Simple Injector?

Juste pour ajouter du contexte, j'essaie de créer tous les gestionnaires d'événements qui savent comment gérer un événement spécifique. Alors voici mon enregistrement de Container :

container.RegisterCollection(typeof(IHandleDomainEvent<>),
    AppDomain.CurrentDomain.GetAssemblies());

Et voici deux classes qui implémentent l' IHandleEvent<T> pour le même événement:

public class Reservation : IHandleDomainEvent<OrderConfirmed>{}
public class Order: IHandleDomainEvent<OrderConfirmed>{}

Alors, quand j'appelle le Simple Injector:

var handlers = _container.GetAllInstances<Func<IHandleDomainEvent<OrderConfirmed>>>();

Je souhaite recevoir IEnumerable<Func<IHandleDomainEvent<OrderConfirmed>>>

Juste pour clarifier, je sais que si j'appelle:

var handlers = _container.GetAllInstances<IHandleDomainEvent<OrderConfirmed>>();

Je voudrais obtenir un IEnumerable<IHandleDomainEvent<OrderConfirmed>> .


Pour les interfaces ayant une seule implémentation, enregistrez en utilisant:

container.Register(typeof(IHandleDomainEvent<>),
    AppDomain.CurrentDomain.GetAssemblies(), Lifestyle.Scoped);

Et en ajoutant le ResolveUnregisteredType suivant à la fin de l’enregistrement:

container.ResolveUnregisteredType += (o, args) => ResolveFuncOfT(o, args, container);

// Function
private static void ResolveFuncOfT(object s, UnregisteredTypeEventArgs e, Container container)
{
    var type = e.UnregisteredServiceType;
    if (!type.IsGenericType || type.GetGenericTypeDefinition() != typeof(Func<>)) return;
    Type serviceType = type.GetGenericArguments().First();
    InstanceProducer producer = container.GetRegistration(serviceType, true);
    Type funcType = typeof(Func<>).MakeGenericType(serviceType);
    var factoryDelegate = Expression.Lambda(funcType, producer.BuildExpression()).Compile();
    e.Register(Expression.Constant(factoryDelegate));
}

Permettra d'appeler:

var handler = _container.GetInstance<Func<IHandleDomainEvent<TEvent>>>();

Réponse acceptée

C'est la beauté de Simple Injector: vous n'aurez jamais à résoudre un IEnumerable<Func<T>> car tout IEnumerable<T> résolu par Simple Injector fonctionne déjà comme un flux .

Cela signifie que lorsque vous résolvez un IEnumerable<T> , aucun des éléments du flux ne sera résolu. Ils sont uniquement résolus lors de l'itération de l'énumérable et sont résolus un par un.

Lors de l'itération du flux, les éléments seront résolus en fonction de leur mode de vie. Cela signifie que lorsque les éléments de la collection sont Transient itérer deux fois le flux provoquera la création de nouvelles instances transitoires.

Exemple:

// Only resolves the enumerable, not the contained handlers.
// This enumerable itself is a singleton, you can reference it forever.
var collection = container.GetInstances<IEventHandler<OrderConfirmed>>();

// Calls back into the container to get the first element, but nothing more
var first = collection.First();

// Since the stream that Simple Injector returns is a IList<T>, getting the last
// element is an O(1) operation, meaning that only the last element is resolved;
// not the complete collection.
var last = collection.Last();

// Calling .ToArray(), however, will obviously resolve all registrations that are 
// part of the collection.
var all = collection.ToArray();

// Iterating a stream will always call back into the container, which ensures
// that the stream adheres to the elements lifestyles. Transients will be
// created on each iteration, while singletons will only be created once.
container.Register<Apple>(Lifestyle.Transient);
container.Register<Banana>(Lifestyle.Singleton);
container.RegisterCollection<IFruit>(typeof(Apple), typeof(Banana));
var fruits = container.GetAllInstances<IFruit>();
Assert.AreNotSame(fruits.First(), fruits.First());
Assert.AreSame(fruits.Last(), fruits.Last());

// Even other collection types such as IReadOnlyCollection<T> behave as streams
var col = container.GetInstance<IReadOnlyCollection<IEventHandler<OrderConfirmed>>();

// This gives you the possibility to get a particular item by its index.
var indexedItem = col[3];

Vous trouverez plus d'informations sur l'utilisation des collections dans Simple Injector ici:



Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow
Est-ce KB légal? Oui, apprenez pourquoi
Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow
Est-ce KB légal? Oui, apprenez pourquoi