7
votes

C #. Comment injecter plusieurs instances d'une dépendance à l'intérieur d'un objet?

J'ai la classe suivante (partie de celle-ci):

class SearchViewModel : BaseViewModel<SearchResultItem>
{        
    private readonly IDownloader _downloader;        

    public SearchViewModel( IDownloader downloader)
        : base(model)
    {
        _downloader = downloader;
    }

    private void Download(object sender, DoWorkEventArgs e)
    {
        _downloader.Download(item);
    }
}


3 commentaires

Qu'entendez-vous par «multiples instances»? Quelle boîte à outils / bibliothèque utilisez-vous pour DI? Si NInject, pourquoi pas kernel.get () Par exemple, après avoir configuré une liaison pour iDownloader ?


Je pense que cette réponse a une assez bonne description des alternatives - Stackoverflow.com/a/5460840/33969


Peut-être que "plusieurs instances" n'est pas le meilleur titre. J'ai besoin d'une nouvelle instance de classe Downloader avant le téléchargement () a été appelée.


4 Réponses :


4
votes

La mise en œuvre dépend évidemment du conteneur que vous utilisez, mais si je devais faire quelque chose comme ça dans Autofac, je ferais probablement cela:

public SearchViewModel(Func<Owned<IDownloader>> downloaderFactory) 
    : base(model) 
{ 
    _downloaderFactory = downloaderFactory; 
} 

private void Download(object sender, DoWorkEventArgs e)  
{  
    _downloaderFactory().Value.Download(item);  
}  


3 commentaires

Merci, j'utilise l'unité et je vais chercher des caractéristiques similaires.


Passer Func <> est une très belle solution. Je ne l'ai jamais vu auparavant. Mais je pense que l'utilisation de la classe de conteneurs à l'intérieur de l'objet entraînerait une nouvelle dépendance. Une autre question: Pouvez-vous partager votre expérience où et à quel point l'enregistrement du délégué? Merci encore.


Ceci est une excellente amorce pour les différentes manières que vous pouvez enregistrer et résoudre les dépendances dans Autofac: Code. google.com/autofac/wiki/relationHipTypes



0
votes

Je ne suis pas sûr que je comprenne complètement la question, mais si vous voulez juste une nouvelle instance par fil, vous pouvez généralement lier avec cela spécifié. Par exemple, dans NIject, vous spécifieriez

Bind<IDownloader>.To<MyDownloader>().InThreadScope();


1 commentaires

Merci pour votre réponse. Pouvez-vous fournir un exemple pour mon cas?



8
votes

Pourquoi pas seulement faire du main à une usine? Ceci est un modèle très courant avec un code injecté de dépendance.

class SearchViewModel : BaseViewModel<SearchResultItem>
{        
    private readonly IDownloaderFactory _factory;        

    public SearchViewModel( IDownloaderFactory factory)
        : base(model)
    {
        _factory = factory;
    }

    private void Download(object sender, DoWorkEventArgs e) 
    {
        _factory.Create().Download(item);
    }
}


2 commentaires

Merci. Je pense que l'usine est un bon moyen de le faire, mais nous ne suppriment pas la dépendance - nous le déplacons dans un autre endroit.


@Yevhenmartynov La dépendance doit existe - il n'y a pas d'autre moyen d'instancier! Nouveau ou à l'aide du conteneur sont vos seules options. C'est l'un de ces cas lorsque le principe de «racine de composition unique» est tout simplement vous causer de douleur. Je suggère une légère modification de la règle: laissez le conteneur d'être utilisé à la racine et dans les usines, et c'est tout.



0
votes

Semblable à la solution de Matt Hamilton, mais pour Microsoft DI Contener.

Définir un Func code> Constructor Paramètre: P>

serviceCollection.AddTransient<SearchViewModel>(s => 
    new SearchViewModel(() => s.GetRequiredService<IDownloader>()));


0 commentaires