
Dependency Injection in .NET with Steve Collins
Durée: 48m33s
Date de sortie: 18/09/2021
In this episode, I was joined by Steve Collins to chat all about dependency injection in .NET. We (well, Steve!) demystified terms such as dependency inversion and inversion of control containers, and then delved into the world of dependency injection in .NET, covering scopes, and much more…For a full list of show links, see the website here
Hey, everyone, welcome to the Unhandled's Exception podcast. I'm Dan Clark and this
is episode number 24. And today I'm joined by Steve Collins to chat all about dependency
injection in .net. Now, Steve is an independent software architect and developer, a blogger
et un public speaker. Il a fait beaucoup de talks en tant que diverses groupes de
UK et aussi des conferences d'EDD, qui sont, je pense, initialement, de ce que nous avons
rencontrés.
Oui, je pense que c'était d'EDD redding. Je pense que nous avons rencontré, oui.
Oui, je pense que nous avons rencontré quelques de ces groupes, et vous avez aussi fait
ce année NDC London, qui est assez grand.
Oui, c'était très excitant. Juste que j'étais virtuel, plutôt que en personne,
mais c'était encore un peu de faim dans le cap.
Oui, c'est certain. Je ne sais pas si c'est possible de retourner en physique, mais
peut-être le prochain année.
Je pense que c'est passé.
Oui, les choses sont en train de commencer. Je ne sais pas ce que je vais faire avec
Donald Oxford, mais les choses sont en train de aller en physique. Nous allons voir ce
qui se passe.
Bien, donc, oui, un grand bienvenue à la show. Et je pense que ce récord de podcast a été
un temps long de venir, n'est-ce pas?
Oui, je pense que c'était en février. Nous avons parlé, et les échanges ont
juste été en route.
Oui, c'était assez bien timé, parce que en février, vous avez fait un talk similaire
à Donald Oxford.
C'est un groupe.
Je parle tout de ça, donc vous m'avez donné un peu de source pour le prép.
Excellent.
Cool.
Donc avant de commencer, je vais faire ce épisode.
Je l'ai mentionné et ceci va au Dave Williamson, qui est Dave W039 sur Twitter.
Et il a dit, juste écouté un fan de fellow Jeppreins Rider, à Dragon, donc à Dragon
et à Dragon.
Dragon est un podcast où il parle à Martin Ballio et Kira Skragan sur le code Rider
avec moi et plus.
C'est bien d'avoir entendu.
Donc il a referé l'épisode 22, donc merci pour le tweet, Dave.
Donc je suppose que les développeurs de maintenant ont probablement utilisé l'injection
de la dépendance dans un autre format.
Mais il y a plein de termes relativement liés à la dépendance, l'inversion, la
conversion de contrôle, les containers et les autres.
Donc est-ce que les termes de termes sont bien mises à commencer avant de se dégager un
peu plus tard ?
Oui, bien sûr.
Peut-être que nous allons commencer avec la conversion de contrôle et la dépendance de la
principle de la conversion, qui est assez bien, le même chose.
Steve Smith a une bonne phrase qui s'amuse à la façon dont nous faisons les choses,
qui est de nouveau, c'est de la glace.
Vous vous récolter des codes, vous vous amusez un objet, vous avez le fait et si c'est
disponible, vous vous destruitz dans votre propre code.
Mais le problème avec ça, c'est que votre code, cette nouvelle instantiation, est
embedie dans votre code.
Vous n'avez pas de la réplique, ou de l'obstituer quand vous voulez tester.
Donc quand vous regardez les choses comme les principes solides, qui parlent de la
dépendance de la principle de la conversion, puis avec ça, ce que vous faites, c'est
dire que, en fait, en vous enantant, je ne suis pas expectant d'avoir quelqu'un d'autre
pour le nouer pour moi et je vais consommer ce qu'ils ont donné pour moi.
C'est donc la principle de la dépendance de la conversion, ou de la contrôle de la conversion.
La dépendance d'injection est un peu la jing-jang-jang à ça,
dans que la dépendance d'injection est la chose qui va vous donner l'objet.
Ça va prendre du temps de vous renouer.
Ce n'est pas un grand tarce, mais si la chose qui a été réveillée a
plusieurs dépendances, ça crée le grapho d'objet,
A qui va créer B, C qui va créer D pour vous.
C'est donc la version de contrôle de la conteneur qui fait ça pour vous ?
Oui, mais il tend à juste commonly être appelé la version de contrôle de la conteneur,
ou la dépendance d'injection de la conteneur, la dépendance d'injection du service,
donc beaucoup de noms, mais ils sont plutôt brûlés au même point.
Regardant nos notes de Google Docs,
beaucoup de choses que nous allons parler de sont la dotnet IOC, la version de contrôle de la conteneur.
Je sais que, il y a quelques années, j'ai utilisé le default pour les uns de la troisième partie,
comme l'injection ou l'autofac.
Je pense que l'autofac est mon préféré depuis une longue période.
Mais maintenant, je me donne un pouce de Steeve, je ne peux pas le voir, mais...
Mais aujourd'hui, je tend à juste défaut de la version de contrôle,
parce que ça me donne tout ce que j'ai besoin, tout ce que je fais est dans la dotnet.
Est-ce que c'est ce que vous recommeniez aujourd'hui,
ou est-ce que l'autofac donne plus de choses ?
Oui, c'est intéressant de vous dire ça,
parce que comme vous, avant le Core, et évidemment le 5, 6, etc.
Nous sommes maintenant, en fréquence,
j'ai utilisé l'autofac priori que j'ai utilisé l'unité,
comme bien des pratiques et pratiques.
Et quand le Core a été utilisé, j'étais habillé à l'autofac.
Donc j'ai vu cette nouvelle chose, mais je pouvais voir que vous pouvez utiliser l'autofac avec ça.
Donc j'ai juste carried sur l'utilisation d'autofac.
Et un peu comme vous, vous avez juste sorti,
gradually, pendant quelques mois, je faisais...
Je n'ai pas utilisé vraiment l'autofac,
l'autofac, le container de boxe, on ne peut pas le faire.
Donc avec ça, j'ai juste dropé,
et j'ai commencé à faire avec l'autofac container,
qui a commencé avec le Core.
Vous trouvez que, quand vous l'avez dropé,
est-ce que il n'y avait rien à l'autre, ou est-ce que c'était juste le même ?
Oui, il y a quelques choses à l'autre,
donc dans le tout, je listais quelques choses.
Le Core, je le referais toujours,
mais j'ai dû le refermer,
juste le Core.
Maintenant, ils sont en Core, le Core et le Core 6.
Le boxe de l'autofac,
est juste en gestion constructeur.
C'est tout ce qu'il faut faire.
Si vous utilisez le Core,
vous avez aussi une injection méthode.
Donc si vous avez un controller de l'autofac,
et vous avez un paramètre qui est dans un méthode d'action,
vous pouvez le décorer avec l'attribut de services de la frontière,
et l'autofac de l'autofac va prendre soin de l'autofac.
Ce n'est pas le container qui fait ça,
il fait des trucs de l'autofac pour parler à l'autofac,
pour vous faire voir.
Vous avez aussi une injection de l'autofac,
où vous avez un objet,
et ensuite vous vous setez les propriétés du container.
Et puis, vous avez également une injection de naine ou de quide,
où, qu'il n'y ait que un type de ce type,
ou un type d'interface,
vous dites que vous avez un string,
ou un constant, ou un enum,
et l'autofac qui a registré un service particulier
est contre ce nom, par exemple.
Le service de l'autofac ne fait pas ceci à l'écran,
maintenant, des choses comme l'autofac font les choses,
et ce que vous pouvez faire, c'est que,
vous pouvez mettre les deux choses ensemble.
Donc, vous avez le service de service standard,
qui est l'autofac,
mais vous pouvez le faire,
donc que quelque chose comme l'autofac ou l'unité,
ils font l'actualité de la nouvelle,
et passent le service au container,
mais ensuite, vous pouvez accéder aux méthodes
sur les trois parties,
pour aller faire les choses fancy,
que le .NET ne fait pas.
Maintenant, Mark Siemen a appris un nom pour ça,
et il s'appelle Microsoft,
un container conformé,
qui est un sort de façon fanciale,
c'est le nom le plus commun de la fonctionnalité
que Microsoft a déterminé,
c'est ce qu'ils veulent faire,
et ils n'ont pas vraiment pris le nom plus tard.
En regardant la version de la dépendance,
je me souviens que, il y a beaucoup d'animes,
il y a eu une conversation sur les types différents,
vous devriez être injectés
par l'interface d'abstractions.
Je me souviens de ça,
on a parlé d'une façon,
que vous ne devriez pas être injectés en type concrétien,
parce que,
ce qui se passe,
si vous voulez changer de type différent,
ça vient de solides principes
sur la substitutabilité,
parce que si vous vous intervient en,
disons,
Wigita,
et vous injectez,
et vous voulez venir en,
disons, Wigit B,
vous devez réécrire votre classe.
Ça vient de la principale solidité
sur les abstractions
et de différentes manières
de les être injectées.
Donc, évidemment, vous avez deux manières de faire ça.
Vous pouvez utiliser d'abord les classes d'abstractions,
si c'est nécessaire.
Mais les gens tendent à
les faire en utilisant les interfaces.
Ça vous donne
votre polymorphisme
de pouvoir substituer les choses,
et ça vient de la principale substitutabilité
et, après,
les principes d'interface de la ségrégation.
Je pense que ça doit être un peu plus de temps.
Je sais que c'est un sujet
contraintraveuse
avec des gens qui sont très interdits,
mais les livres de mocs,
comme M.O.Q.
et de substitutes,
je suis personnellement
un grand fan de les livres de mocs
et juste de pouvoir moccer
le détail de la implementation
dans les tests.
Et le test,
de pouvoir vérifier si quelque chose a été appelé
ou juste dire
si ceci est appelé,
puis retourner à ce data.
Je le trouve très fort.
Oui.
Et certainement,
les choses où c'est un fonction
ou vous voulez juste une particularité de propriété testée,
c'est bien.
D'où
je tend à profiter plus
en évaluant un concrétisme
qui est juste un peu plus
que un moc,
c'est si vous voulez,
pour exemple,
dire si c'est été appelé
tant de fois,
vous gardez un compte
dans votre propre implementation
pour que vous puissiez dire
oui, ça a été appelé tant de fois,
ou il y a un comportement expectant
que vous ne pouvez pas
juste faire
par exemple, un moc,
ou par exemple.
Oui, je l'ai souvent utilisé
pour vérifier
comment,
exactement,
il y a tant de fois,
il devrait être appelé.
Mais le moc,
c'est probablement l'un de nous qui pourrait avoir
un tout épisode.
Oh, mon Dieu.
Je me souviens,
l'année dernière,
j'ai fait un tweet
sur le moc,
je pense que c'était un moc,
c'est juste de l'interesse
de ce que les meilleurs
de la faveur étaient.
Et,
wow,
c'était un mien de repos.
Oui,
mon seul moc est un substitute.
C'est celui que je
tend à apprendre.
2 grands projets
que j'ai travaillé sur recently
ont utilisé le moc,
parce que c'est ce que
ils ont utilisé.
Et je trouve que
les meilleurs mocs
et le substitute
ont fait la même chose.
Et je suis kind de
utilisé pour les meilleurs syntaxes.
Donc je ne m'en souviens pas
de quel moc je l'ai utilisé.
Mais,
en tant que plus intuitive
le syntaxe,
je pense,
c'est où la chaleure de substitute est.
Oui, et je pense que
quand vous parlez de Jason Boc
dans un précédent épisode,
il a dit,
il a regardé le moc
et il n'a pas regardé
le substitute
et le moc.
Et je me dis,
ah, je le vois.
Oui, je voulais regarder
son moc,
c'était un moc.
Non, non, c'était pas ça.
C'était un moc ?
Un moc ?
Oui, c'est un moc.
Oui, c'est ça.
Je pense que
il a réétenu ça récemment.
Les généreurs de source
étaient le sujet
de l'épisode podcast.
Donc il a réétenu
que d'utiliser les généreurs de source.
Et apparemment,
c'est un speed increase
qui fait le sens,
parce que vous ne faites plus
que ça en un moment.
Oui, et certainement,
c'est intéressant que Microsoft
est maintenant regardé
le serialiser de Jason
pour le net 6
et réétenu
avec les généreurs de source.
C'est un incliné
massive de performance,
apparemment.
Je peux l'imaginer.
C'est quelque chose
qui se passe par réflexion.
C'est plus dur
en un moment,
en utilisant la réflexion,
il se passe par compagnie.
Donc le temps de la réunition
va être
0, j'espère.
Oui.
Je pense que c'est intéressant
que les gens
ont dit,
qu'est-ce que c'est
le réjecteur?
Parce que
vous avez des différentes
façons de rouler le réjecteur,
il y a l'interprétation
du temps de la réunition.
Mais ensuite,
vous pouvez faire
quelques méthodes
où vous dites
« compiléz-le
à la start-up en mémoire
ou compiléz-le
à un assemblée.
»
Ce qui me fait
de s'éteindre
pour devenir
un source-généreur de C-Shark.
Oui,
c'est certain.
Je pense que nous allons
trouver plus et plus
de cas de cas de source
pour les généreurs
et les gens qui vont avoir
plus et plus d'idées.
Je pense que c'est une bonne
chose pour tout.
Tout ce qui est
un source-généreur
à l'époque,
c'est que
ces idées
ont la visibilité
d'essayer des choses différentes.
Oui,
je pense que c'est
une récomposée de Github
qui est appelée
quelque chose de comme
le C-Shark
et il y a
beaucoup d'exemples
dans la travail
que les gens ont fait
ou des pointeurs
pour les récomposés de Github.
C'est
un des points
pour les notes de la show.
Donc, je pense que
ça semble que les gens
vont être éprouvés
par un peu d'exemples
avec tout ce
injection de dépenses
sont les scopes
et les temps de vie
et tout
et je peux dire
que les gens ne peuvent pas
voir votre expression maintenant
mais je peux dire
que c'est
un gros.
Oui,
donc,
les containers
et certainement les Dottnet
supportent
trois bonnes tempses basiques.
Vous avez lu
le lifetime de Singleton,
le lifetime de Transient
et le lifetime de Scopes.
Donc,
avec Singleton
c'est un peu
similaire
à l'âge de la patine
de Singleton
que Highlander
peut être le seul.
Maintenant,
ce qui distingue
des choses comme
la patine traditionnelle
de Singleton
est qu'avec la patine traditionnelle
vous avez à faire
mettre un bloc de plate-d'oeil
pour créer un instant
de singleton.
Vous avez à être
à l'air de la thread.
Maintenant,
John Skeet,
il a écrit un blog
avec des six
ou des sept
différentes manières
pour créer
une patine traditionnelle
et puis,
il a eventually landé
sur le point
où l'on est,
il a utilisé
le type lazier
dans le point.
Parce que ça
t'enlève
en prenant la certaine
de créer des tas de differentes
manières.
Vous n'avez pas
à faire
faire un bloc de plate-d'oeil
quand vous faites
un sigl automatique
dans un containers
parce que vous pouvez
utiliser
tout le point
de poco.
Vous pouvez juste
le régister
comme un containers
pour le premier time
que l'on utilise.
Il va se placer
en bas
et il va être là
jusqu'à ce que le containers
disparaissent.
À l'autre end
de la spectrum,
vous avez des transients
qui sont comme
vos amis de la fête.
Ils viennent
et vont
en tant que
besoin.
Vous avez
quelque chose
qui vous a besoin
d'une instance
et qui vous dit
que vous allez
faire le bloc.
Et puis,
votre chose
disparaît,
le collecteur
de la gare
va le faire.
Il va en faire
et il va
политiquement
la mettre ici.
Vous mıste pas.
en
IN satisfaction
typiquement
bags
de la distance va disparaître.
Pour donner un exemple plus de l'exemple du monde réel,
le monde que les gens sont très familiar avec,
c'est en ASP.NET,
où vous avez un request de HTTP,
la scope commence quand vous vous mettez le service,
ça fait tout le temps,
et puis ça disparaît quand la sponse se démarre.
Je dis que ça s'étend entre les deux,
parce que c'est un peu comme un transient,
dans lequel il y a un temps plus tôt que un singleton.
Mais,
c'est comme un singleton
et dans ce nombre de choses,
dans ce unité de travail,
la scope,
nous allons partager cette même instance.
Donc, juste deux choses pour vous faire comprendre.
Un singleton est juste un pour le processus.
Oui.
La scope est par request.
Si vous utilisez un ASP, oui.
Mais,
la même interface qui est injectée
au cours de l'ensemble des codes,
pour le même request,
c'est le même exemple,
mais deux différents requests.
Deux différents requests,
deux différents instances.
Et puis,
chaque single injecté est injecté.
Est-ce que c'est un instant ?
J'ai compris.
Il y a un instant nouveau.
Oui, c'est correct.
Donc,
quand vous utilisez un scope,
quand vous utilisez cela au-delà
d'un API web,
parce que je l'ai parfois vu,
si vous avez un app console,
et vous avez le host,
la build,
et des blocs,
je pense que ça commence à être scope,
et puis vous avez un scope là-bas.
Oui, donc,
au-delà de l'application service,
vous pouvez faire un scope créé.
Et ce que ça fait,
c'est que ça effectue
une autre instance d'application service,
et vous pouvez accélérer
vos transitions et les single injectés,
mais vous pouvez avoir vos instances
de scope aussi.
Maintenant,
dans le contexte de l'app console,
je ne souhaite pas que vous soyez
nécessairement envers ça,
en tant que,
peut-être,
vous faites quelque chose
de service post,
ou vous faites un
tout-multi-thread,
où différents threads
peuvent avoir différentes instances,
et vous êtes dans les alignements de thread,
et d'autre que ça,
je ne peux pas vraiment
voir que beaucoup d'usage pour scope,
mais les gens qui l'entendent
vont dire,
ah, je dois faire ça.
Pour les listeners,
si vous avez,
s'il vous plaît,
commentez sur le site,
vous êtes intéressés
à entendre tous les différents outils,
mais comme vous,
je n'ai pas vu ça,
c'est pourquoi je ne m'en souviens pas
si c'était de commencer scope,
ou de créer scope,
comme vous le disiez.
Oui, et ça se fait très convaincre,
parce que vous créez scope,
et ça vous donne un container
dont vous avez le service provider,
et ça sort de la fin
et de la hierarchy
pour aller à ce que vous voulez,
pour avoir le temps.
Alors, ça se fait
tout de suite,
dans le main container,
dans ASP.NET,
parce que ce que ça fait,
c'est que,
quand vous avez un request,
il y a un feature service,
et ça t'en fait carenir
la création de scope,
et ça en fait,
il y a le service provider,
qui est un truc
d'aller et dire,
aller et avoir le service scope factory,
créer le scope,
et ça se fait
tout de suite.
Ça fait tout ça pour vous.
En tant que vous êtes concernés,
vous pouvez utiliser des instances scopes
dans le contexte
d'un request de réponse
de l'HGTP,
et au-delà de ça,
vous vous restez de l'autre.
D'où ça se fait un peu tricky,
et on peut venir le voir,
c'est quand vous vous entrez
dans le milieu de la zone.
On peut parler de la milieu de la zone?
Oui, on peut.
Ok.
Donc avec la milieu,
il y a deux manières
de la réglage et de la utilisation.
Donc, quand le code dotnet
s'est arrivé,
il utilise ce qu'on appelle
la base convention de la milieu,
où ce qui se passe
est que vous vous réglez
à une classe,
et cela a un délicat
de request qui est passé.
D'où il se fait un peu confus,
c'est que le délicat de request
qui est passé
à la construction de votre classe,
c'est effectivement un single turn.
Cela crée un instant,
et cela passe au délicat de request.
C'est ce qui vous change
à la prochaine milieu
à la prochaine milieu
à la prochaine milieu.
A votre contexte de HTTP
et d'autres choses
que vous voulez vous faire utile,
vous faites des paramètres
dans le méthode invoke.
Parce que cela se fait dans le voc
et cela se fait tout en refléchissant,
cela est effectivement scopé,
et cela se fait sur un basis de request.
Quand je suis commencé
à faire la première fois
dans la milieu,
je m'ai fait le coup
de la configuration
d'une option snapshot
qui est scopée,
je l'ai injectée
dans le constructeur de la classe
et cela n'était pas changé.
Je ne comprends pas.
Je vais aller en haut
et lire la documentation
dont nos développeurs n'auraient jamais aimé.
Quand je l'ai lu,
je l'ai dit
Ah, ok,
cela devait être le méthode invoke.
C'est un rapier
pour beaucoup de développeurs.
Donc,
quand Doctrack Core 2
est arrivé,
Microsoft s'est allé
en bas avec l'interface
de l'I Middleware
et l'a tout en sa tête.
Donc, avec cela,
si vous avez des dépendances,
ceux qui sont injectés
dans le constructeur
et le contexte de l'HGTP
et le délicat de la request,
ils sont passés par les paramètres
dans le méthode invoke.
Donc, cela se termine
en sa tête.
Mais ce qui veut dire
c'est que vous devez
résister votre middleware
avec le container,
alors que,
dans le méthode conventional
de la middleware,
vous résistez dans le méthode config
et vous utilisez
la middleware à l'intérieur
ou utilisez la middleware.
En utilisant la interface
de l'I Middleware,
vous faites cela
comme part de votre
registration d'injection
et vous faites cela
dans le méthode de services config.
Ça semble que la nouvelle version
est beaucoup plus consistante
avec d'autres moyens
de faire des injections d'injection,
aussi.
Donc, vous vous rappelez
avec les fonctions d'Azure,
comme les fonctions
de la nouvelle Donut 5,
des fonctions isolées.
La chose qui m'a trompé
était que je voulais
injecter l'I Logger
dans le méthode de la
fonction de la fonction de l'execution.
Et puis, ça ne fonctionnait pas.
Mais ensuite, je me suis rendu compte
que la injection d'injection
maintenant fonctionne
dans les fonctions d'Azure
comme tout autre et vous injectez
dans le constructeur,
ce qui est en fait
ce que je normalement
injecterais dans le constructeur.
Mais parce que je m'ai
migréé un project d'Azure
de fonction d'Azure
de pre-Donut 5
à Donut 5,
j'ai toujours eu
l'I Logger
injecté dans le méthode d'actualité
et ça n'a pas fonctionné.
Oui.
Donc,
la base de la base de la base
c'est comme je vous le dis,
il y a beaucoup de troupes
de la base où vous pouvez le faire
de l'une façon et puis
ça change de l'autre façon.
La différence
avec la base de la base de la base
vous faites effectivement
créer un nouveau instant
de la classe de la base de la base
chaque fois que c'est été connu.
Mais le base de la convention
c'est juste le premier instant
qui est créé par la reflection.
Et c'est votre paramètre,
créé par les dépendances
utilisant les paramètres
de votre méthode invoque
qui est la différence.
Donc, je pense que si vous avez un web
sur le qui est absolument
démonter avec beaucoup de requises,
il y a un problème
sur la collection de garbage
et la mémoire
si vous utilisez
l'interface d'I-Middleware
parce que c'est un peu
trop de choses.
Mais, en le fait,
c'est seulement là
pour la respiration
de la réponse de requises.
Donc, si vous avez un petit truc,
est-ce que la génération 0
dans la collection de garbage
est la première fois?
Oui.
Oui, c'est cool.
Je pense que c'est dépendant
de combien de requises
vous avez en plus pour les secondes,
donc, vous avez beaucoup d'eux.
Oui.
Mais oui, c'est intéressant
avec les plus de développeurs
qui ont fait
l'espion de développement
et les web-appiers créés.
Ils utilisent
les injections dépendantes
comme standard.
Quand vous allez un peu plus loin,
je pense que seulement un petit %
de nos casillettes
sont des petits.
Dans le dernier épisode
où nous parlons de la gait,
je pense que Jesse a dit
que 90 % des développeurs
utilisent la gait.
Mais, pour mon expérience,
beaucoup de développeurs
utilisent la gait.
Ils ne comprennent pas
le temps et ne utilisent pas le temps.
Et,
en fait,
c'est comme avec ceci,
que les développeurs d'Ottenet
sont maintenant,
tout de suite,
utilisent les injections dépendantes.
Mais, c'est intéressant
de savoir
comment vous entendez les scopes
ou toutes ces
zones de injection dépendantes.
Oui.
La gait est un bon point
parce que, évidemment,
dans le monde de framework,
où vous avez vos modèles
et les modèles,
je pense qu'ils sont appelés
les modèles HTTP,
les modèles HTTP.
En passant au nouveau gait,
effectivement, ils se font
le même chose,
mais c'est juste
un modèle de programme
qui est utilisé pour l'injection
alors que,
dans le monde de framework,
vous avez besoin de faire
tout le travail.
Et, certainement,
l'année première,
j'ai utilisé
la toute sorte de chose
sur la gait.
Et c'est là
que j'ai fait
le misto avec la gait.
Et c'est quand j'ai commencé
à le faire un peu plus bas.
Et je me dis,
pourquoi pas
cela ne fonctionne,
et je lis le document,
et je me dis,
Ahhhh!
Ahhhh!
Mais,
sur le plus-à-à,
cela vous a donné
une bonne idée
de l'Ottenet.
Oh,
c'est un petit peu pire.
Oui.
Vous avez pensé
de faire un cours de course
en Gait,
ou quelque chose comme ça,
non?
Steve Gordon
a déjà coupé le marché.
Ahhhh!
Donc, Steve
a un cours vraiment bon
sur le cours de course.
Un autre Steve!
C'est comme...
Il était votre premier guest,
non?
Il était mon deuxième guest.
Deuxième guest.
Episode 2,
on avait Derek Comart
et en Episode 3,
on avait Steve.
Et il
fait
un grand nombre de choses,
non?
Oh, mon Dieu,
il fait
mon tête spin,
le nombre de choses,
il se spinne.
On
a besoin de plus de Steve,
non?
Donc,
on a les Scots.
Oui,
on a Steve Smith,
un triomphère de Steve.
Oui,
mais il y a Steve
Sanderson,
donc,
il y a les 4 Steve.
Vous êtes les 3 Scots,
non?
Ahhhh!
serai un lesser Steve.
Il n'y a pas
que les choses
plus les lesser Steve.
Ahhhh!
Donc,
en parlant de
les fonctions d'Ajouard,
je tendais,
j'ai toujours le default
d'utiliser la injection constructe.
Je ne pense pas que je
n'ai jamais
utilisé
d'autres formes d'injection,
c'est juste mon default.
Vous tendez
à avoir d'autres cas de use
où vous trouvez
que la injection constructe
n'est pas une bonne option.
Donc,
avec ça,
ce n'est pas
beaucoup sur votre propre code.
C'est
si vous avez
des classes
qui sont dans
un library
C'est
que quelqu'un d'autre
a écrit que vous voulez
consommer.
Mais c'est
targeté
à l'étranger.
Donc,
ils n'ont pas nécessairement
pensé à utiliser
l'injection constructe.
Donc,
par exemple,
en framework,
on a eu plusieurs classes
où vous vous instantiéz,
puis vous vous
installez un peu de propres,
puis vous vous appelez
quelque chose comme
un init,
ou initialiser.
L'un qui s'est
en framework,
où je pense
qu'il y a
plusieurs bits
et bobs
où,
effectivement,
par votre configuration,
vous vous vous vous vous
vous vousulatez
L'éallumine
lead
un
trac
ou vous pouvez potentiellement utiliser une proche.
Mais ce que vous faites derrière la scène est que vous vous fillez les gâbes
entre faire une injection constructe et une injection de propriété.
Donc, pour exemple, pour faire une injection de propriété,
vous pouvez consommer toutes les dépendances
que vous avez besoin de mettre sur les propriétés, par exemple.
À l'intérieur de cette injection constructe de votre classe,
vous allez réunir cette troisième partie,
mettre toutes les propriétés que vous voulez, coller le nid,
et ensuite retourner à un méthode qui s'appelle, disons,
créer ou construire, par exemple.
Named and keyed est une chose de plus annonceuse.
Et parfois, c'est refermé comme un smelter code,
ou une imprimante pratique.
Mais il y a des fois où vous le faites.
Et ce qui m'a fait me dégager un peu plus,
c'est que j'ai eu un scénario en particulier
où je l'ai lu sur un database d'infraînement
et que je voulais utiliser des classes de mappings de mappings
pour maître des valeurs différentes
pour utiliser des calculations différentes.
Il y a plusieurs manières que vous pouvez faire.
Mais ce que je voulais faire, c'est prendre un string
qui est venu au database et utiliser ça
pour voir quel maître que je voulais faire,
et puis passer le reste des valeurs
dans ce maître pour aller y aller et y aller,
à l'instant.
Oui, vous pouvez faire ça en autofac et
en diverses choses comme unité, je pense.
Mais certainement, le .NET ne peut pas faire ça.
Et ça m'a rendu un sort de maître
en travaillant sur comment je peux faire ça.
Et je l'ai écrit un blog sur ça,
sur comment vous pouvez aller en bas et utiliser quelque chose
qui ne donne pas beaucoup de publicité à ces jours,
et c'est de l'élégance.
Parce que avec le .NET container,
les gens pensent sur les interfaces et les classes concrètes.
Mais l'élégance est derrière les scénarios.
Quand vous vous faites au niveau de l'AO,
il crée une classe derrière les scénarios.
Donc c'est une référence.
Mais pour donner une information full,
un élégant est un signe de fonction.
Donc, dans le .NET,
vous êtes probablement familiar avec les choses comme
le funk et le funk T, le funk T1, le funk T2, etc.
ou l'action.
Ce sont des délégués prébates.
Et en bas en fréquent, on a entendu des choses comme
les handlers d'événement.
Ces sont tous délégués.
Ils se sont conformés à un signe particulier.
Donc je suis là à penser,
si j'ai utilisé un élégant et disais
que je veux passer dans un string,
et que je veux retourner à un particular appareil,
si je peux réagir un élégant
et avoir le containers pour travailler
ce que je veux en bas sur ce string,
alors ça fait le même chose
que de la nommage ou de la quête.
Donc j'ai lu un blog,
et je suis sûr que nous pouvons mettre
les notes de la show.
Mais finalement, j'ai terminé par ce point
où vous injectez l'élégant
dans votre classe de consommation.
Et là, vous vous arrêtez.
Et puis quand vous voulez aller
appeler le mappère,
par exemple, vous invoquez
par le paramètre,
un mappère A,
et vous repartez en instance
de mappère A.
Donc, ce sont les choses où vous vous
commencez à bouger au-delà des realms
de ce que le container conformé,
le Microsoft-1, peut en fait.
Mais il y a des round-tables pour ça.
C'est vraiment sympa, parce que ça vous semble
que vous êtes créant une factory,
mais sans créer une classe
et l'interface, et tout.
D'où j'ai tendance à faire
ce genre de choses dans le passé.
J'ai créé un I, un factory,
et une implementation
qui a un méthode pour rétablir quelque chose.
Mais si vous pouvez le faire,
et que vous faites un peu plus fonctionnel,
et que vous faites le rédacteur,
vous faites juste le délégant.
Ça ressemble beaucoup plus.
Et d'autres, vous utilisez pour ça,
et je suis sûr qu'on va parler de test.
Mais, un de mes vrais héspits
de la vie,
est de s'avoir fait un délégant
maintenant,
bâché à une classe.
Parce que vous ne pouvez pas le tester.
Maintenant,
plusieurs personnes ont dit,
que vous allez faire, et que vous faites un interface,
comme une abstraction, et puis vous avez un méthode
qui dit « GET TIME ».
Mais le délégant de la façon dont vous pouvez
prendre beaucoup de la plate-d'huile,
et dire, je n'ai pas un délégant qui dit
« GET DATE TIME ».
Il ne faut pas que les paramètres,
et il vous donne un date-time.
Et puis, dans votre registration,
dans votre classe de start-up, pour exemple,
vous pouvez avoir une expression lambda
qui dit, quand je prends un de ces délégants,
juste appelez « SYSTEM DATE TIME NOW »
et retournez-le.
La joie de ça,
c'est que nous avons parlé de l'abstraction
plus tard, c'est que vous utilisez une abstraction,
il n'a pas besoin d'un délégant.
Quand vous faites un test pour ça,
vous pouvez créer votre propre expression lambda
qui dit « RETURN A FIX DATE TIME »
que vous pouvez tester
dans votre unité test.
Je suis d'intérêt, si vous vous registrez
un délégant avec votre container IOC,
si votre délégant est légèrement
juste le signe de méthode,
ce qui s'arrête entre
deux différents délégants,
qui ont été séparés dans le même signe.
Donc, ça revient à la différence
entre le funk générique,
par exemple, comme délégant,
parce que c'est très générique,
et le délégant C-Sharp
comme vous avez dans
.NET Core 1.
D'accord, le framework.
Quand ça s'est passé,
parce que quand vous créez des délégants,
vous vous donnez un nom très spécifique,
et effectivement, c'est presque comme un nom classique.
Ah, j'ai compris.
Vous pouvez avoir plusieurs délégants
avec le même signe,
mais si vous vous expliquez,
je vais enregistrer contre ce nom délégant,
et je vais enregistrer le nom délégant,
vous avez créé
la couple de la même chose entre les deux.
Ah, j'ai compris.
C'est un nom délégant,
et ce n'est pas le signe
qui est en train de se battre, c'est le nom.
Cool, ça fait du sens.
Oui, oui.
Parce que si vous avez alors
entendu quelque chose qui s'est consommé,
juste que vous l'avez expéré comme un fonction anonyme,
alors c'est là
qu'il n'a pas de fonction,
parce que vous ne pouvez pas
juste enregistrer la fonction.
C'est le délégant,
si vous regardez le nom délégant,
ça va créer une classe.
En taking this to maybe a further extreme,
where just going much more functional,
where a lot of functionality
is injected as higher order functions,
rather than having all interfaces everywhere.
So I guess that's probably another question,
it's what word does the balance come between
that you see a lot of dotnet projects where
pretty much every single class
has an interface just to follow this pattern.
Do you find that sometimes that's overdone
is the...
I think that some people argue
do you need dependency injection at all?
And I think if you've got a really tiny
little console app,
then do you really need dependency injection?
But then you walk it back and go about testability,
and to do testability you need
some kind of abstraction.
So I've seen various things on Twitter
and blog posts about why is it you've got
all these hundreds of interfaces
and abstract base classes,
and these classes why not inject the concrete.
But by injecting the concrete,
you are doing the type coupling.
So it does feel sometimes
like you're writing a lot of boilerplate to do these things.
The joy of the delegate way of doing things,
and it's effectively a functional way of doing it,
is if you only have a single
method on say a class,
then why not just write it
as a function?
Yes, yeah.
Because then you don't need all this other boilerplate
with it. But if you've got multiple methods
and properties and all this
thing, I think you are pretty much bound
to having a class
and an interface. But also doing the interface thing,
if we come back to the solid principles,
you've got things like interface segregation
principle, where
if you've got a class that has got
certain different things, but you may
only want a subset of that functionality,
then you can split it out into multiple
interfaces.
That gets interesting with dependency
injection. Because if you try
and register a class against multiple
interfaces,
by default, if you're doing say, add single
turn interface service,
this class,
you'll get a different instance of that
class where you call via the different interfaces.
So with that, what you have to do
is actually register the concrete class
with the
container. But then what you do
is you then write other registrations,
one for each interface, but then
you use a lambda expression that uses the service
provider to go and get
that one concrete class that is created.
So that way, instead of having
say, if you've got a class with three
interfaces and having three instances, you just
get that one instance back. Because you've
used the service provider to resolve back to that
original concrete class
to go and then, but then you're exposing
it through the three interfaces.
I understand, I think.
I think this is where audio
becomes more difficult.
I'm actually worried because I think I do understand.
So that's going to...
I guess that's a good sign, isn't it?
So you mentioned about a single class having multiple
interfaces. Quite often I've hit scenarios
where I've got an interface
where I've actually got multiple
implementations of it.
But depending on what scenario
and code I want to inject in different
implementation details. Is there a
way around that without using
factories and that kind of thing?
So what you can do
if I take a step back
so say you've got
interface A and you've got class A
class B, class C
then if you go and say
add singleton
interface A, class A
add singleton interface A, class B
and so on, so on, so on.
Then the .NET container works on the
basis of a lasting wins principle.
So if you're
consuming class says I want
one instance of interface A
then whatever the last one you
registered will be the one that gets
served up. But
what you can do
is you can say
I want an I innumerable
of interface A
and what you'll get is you will get an
innumerable of all the things that got
registered with the provider.
Now what you may then want to do
is it depends on how
you want to differentiate those things.
You might have some property on there
where you can differentiate them
and then go and create a dictionary
or you may have each one implement some
other interface and you can test each one
for the interface. What I wouldn't necessarily
advocate is testing what the concrete
implementation name is
because that may be a never shift in
sands underneath you. But by doing
that I innumerable
you get all the different implementations
and then it's up to you how you sort it.
What you will find though is if that
I innumerable you'll get them in the order
that they were registered with the container.
So if the order
you get them is of some consequence
those concrete classes you may
want to implement I comparable
something like that that gives you some kind of sorting
so you can do a link query and say order
by whatever
you want to order it by to get them into the right order.
Gotcha, gotcha.
I have tended to do
like a dedicated factory
things to get around that. But yeah it sounds
like there's lots of different ways around and it's just
knowing them all so you know
which one is the best one for that particular
scenario. Yeah.
And certainly I'm not saying that don't go
use a factory for example because you could
embed all that logic inside a factory
and it kind of comes back to what we were talking
about with named or keyed
injection in that you've got something
where you say I want one of these
abstract factory
please give me what's most
appropriate based on some kind of criteria.
Yeah, yeah, definitely.
Definitely.
With these IOC containers
if you've got a concrete type
which implements I disposable
so it needs to call this dispose method
how is it handled by the IOC containers?
So in most cases
the container will go and dispose
an instance for you if it detects
that there's an I disposable interface on that particular class.
But there's a couple of times
where it won't necessarily do that for you
and one of those times
is if you use a signature
where you go and instantiate that class
within your registration code
and what happens there
is because the container hasn't
instantiated it itself
it doesn't know it's got to dispose of it.
What there is is there is a backdoor
way to it that Andrew Locke put on a blog post
and that is the I host
application lifetime
and that is automatically registered
and I think that is part
of ASP.NET's registration.
But what that does
it has a property on there called application stopping
and that in turn has got
a register method.
What you can do on that
is you can register for the application shutdown event
and inside there
you can ask it to give you
the instance that the container has resolved
for you and then you can call the dispose
on that. But that is really
messy.
So what my personal preference
would be to do is if you've got a situation
where you need to new up something
and pass some parameters in from outside
the container is, we've talked about factories
before, is effectively create
a factory class to do all that heavy
work for you and then call
the factory method on that
from within a lambda expression
within your registration
and that will trigger the I disposable
to get called.
Yeah, that makes sense.
Yeah, I think sometimes whilst you wouldn't want
to overuse factories, sometimes
I've seen developers that aren't used to the factory
pattern at all really tying themselves
in knots over trying to use dependency
injection in really complicated ways
when a simple factory would have just
solved a lot of problems. So it's definitely a good
thing to have in your toolbox.
Before we move on to dev tips,
are there any
common mistakes that you tend to
find developers make with dependency injection?
So not so much a common mistake
but an unfortunate thing
that can happen is
say you've got code bases that get merged
together, so you've
done a git merge and something's
gone wrong, so you might see
a registration of say an interface
being done with class A
and an interface then with class B
within the same start up
registration process. Now
I mentioned earlier that the
container out the box works on the last
in wins. So if that merge
has gone wrong and you really wanted
class A registered
and class B is below it
because the git merge has gone wrong, then
that could be a problem but hopefully code review
would pick that up.
But
it can also happen when
you're depending on new get packages
and it comes down to the person
who's written the new get package
behaving themselves and using the right
way of doing some registrations.
But also which order you
use the if it's say done through an extension
method, whether you've called
their extension method before or after
your registration.
The way to get round that is there's
alternatives to things like add singleton,
add transient etc. And that's the
try add versions
of them. So as we've said
by default it's last in wins.
Using try add it's a bit like the try
add with a dictionary
in that it flips it and says
if I've already got this I'm not
going to register it again. So it
becomes from a last in wins to a first
in wins because even if you register
200 things after that first registration
it's that first one that's
going to get served up.
That is useful if you're writing
a new get package and an extension
method that does the registration for other people
because you don't know what
other people may have done
and how they're going to consume it. So
if you're writing a new get package it's better to use
the try add
registration methods rather than the straight
add methods.
That makes sense.
So that was going to be my question
before you mentioned more about new get packages
would you recommend everyone do that but it sounds
like if you're a library author
use try add otherwise just use the normal
add singleton or add transient.
Yeah and
I think it's how well
you know that code base
as to which way you jump. If it's
sort of a code base it's got lots of extension methods
calling left, right and centre to other modules
that other teams have written.
You may want to use try add
to start with
and then if you're not getting the thing that you're expecting
then
maybe you need to sort of work out
well why am I getting this other thing? What have I already
registered?
Either myself or another team's done it through an
extension method before
you just go and use the add
method because you may
not necessarily know
what dependencies there are back further
through the chain that if you're putting yours in
may get upset
by your implementation.
I see. Is there any way
just going back to your first example of like merge conflicts
is there any way you can tell
the IOC container that
if any same interface is registered twice
through an exception?
I'm not aware
of one. I'm just trying to think
I'm not aware of it
because it's got this sort
default lasting width and
because people write extension methods
and you could have any number of registrations
coming in.
I think it works on that lasting width basis
because if you get an exception thrown
during that registration process
everything's going to just stop.
Yeah I guess
it's the typical it depends isn't it?
I think in my own code base where I'm registering
my own interfaces
thinking of what I would want it to do
I think I would want it to throw an exception
if I registered the same thing twice
but then as you say
you've got other things
registering things as well like new get packages
and things
so again
I use that first an awful lot
it depends.
It's the IT guru's default phrase
it depends.
Alongside turn it off and back on again
it depends.
Cool so shall we do dev tips?
Yeah sure
So my dev tip is a site called
Sharp Lab IO
and what that is useful for
is you can put code in and try and debug
but what it does is it gives you
IEL disassembly
and it's really useful for things like
so in C sharp you have
this concept of things like lowering
where you might write your code in a certain way
but behind the scenes it gets
lowered down to slightly different code
and you can see what actually
will get generated from your C sharp code
it's also really useful
if you're doing things like Rosalyn
analysers or source code generators
it has a thing where you can see the syntax tree
and it graphically
shows you with sort of a tree view
of the syntax tree of what your code is doing
so you can cut and paste into this
now I know there's some tools built into
Visual Studio but if you've got something like Visual Studio Code
or I don't know whether there's a similar tool in Rider
it's a way where you can just cut and paste some code in
and sort of say this is
what it's going to lower to
and also it supports
lots of different versions of C sharp
so you can see
how it works in different versions of C sharp
including all the upcoming
sort of versions that haven't necessarily been released
I need to play around with more of these
web based tools like this because
I kind of like, because I've been a linkpad user
for quite a long time so
if I just need to do a quick bit of
proof of concept code then I do it in linkpad
and linkpad like it's got the IL
that you can basically drill down on things
but I know that more and more recently
I've been hearing a lot of these web based tools
like sharplab and I think there's a few others
which seem to have
got really good lately
so I need to have a play
yeah
so my dev tip is
basically to
it sounds like a simple one but to actually test your code
before passing it on
and I don't mean write automated tests
well I do write automated tests
but that's not what I'm talking about here
I just mean, and this might be me being rubbish
but I find that quite often
even with changes that seem
pretty safe and that works
locally they might fail
for some other reason when deployed
maybe configuration or environment
differences and you might be lucky
to have a QA team that does this for you
but relying on your QA team
and not testing yourself
anyway just waste a lot of time
going backwards and forwards
and if you are lucky to have a QA team
then I would recommend
challenging yourself that
they will not find any bugs in your code
like make it a challenge, make it a game
and I do also highly recommend
that teams have a definition of done before tickets get resolved
and testing the code
actually does work
should definitely be one of those items
so basically don't just push to get
then immediately resolve the ticket
assuming that CICD will deploy it
and everything will be rosy
which is something I see happen quite a lot
Cool, so before we wrap up
is there anything else you would like to mention?
So if people want to get
touch with me I tweet quite a lot
at stevetalkscode on twitter
and that's also the name of my website
stevetalkscode.co.uk
where you'll probably find quite a few blogs
about dependency injection and I'm starting to tinker around
a bit more with source code generation
which obviously Jason Bogd
spoke about in a previous episode
Yes, I think actually
we all deved it with a shout out lab
it was on Gabal from somewhere
and it might have been him that mentioned it
in maybe another conversation somewhere
for the same reason you mentioned
with basically seeing the syntax tree
Yeah, I've been playing around with
source code generators
but I've gone very much down
writing it as
complex strings
doing replaces which gets quite hideous
but if you're having to go
and look at sort of
listen to triggers of certain things happening
then that's when the syntax tree
and the semantic trees
start to become much more interesting
I can imagine, imagine
Cool, well that actually has been saved
thank you so much for joining us
it's been absolutely amazing having you on
and I'm sorry it's taken so long
Thank you for having me Dan, it's been a pleasure
and really enjoyed myself
Really thank you and thank you everyone for listening
and a quick reminder that this podcast is sponsored by Everstack
which is my own company providing
software development and consultation services
for more information visit
Everstack.com
and if you enjoy the podcast please do help me spread the word
on social media, I normally use the hashtag
unhandledexception and I can be found
on twitter at Dracan and my DMs are open
and my blog danclott.com
has links to all my social stuff too
and we will include links to all the stuff
we've mentioned today in the show notes
which can be found on
unhandledexceptionpodcast.com
Sous-titres réalisés par la communauté d'Amara.org
Sous-titres réalisés par la communauté d'Amara.org
Episode suivant:
Les infos glanées
TheUnhandledExceptionPodcast
Tags
NDepend with Patrick Smacchia