Comment l'injection de dépendance pourrait-elle être intégrée dans le langage? [fermé]

10

J'ai réfléchi un peu à la façon dont l'injection de dépendances pourrait être mieux intégrée directement dans un langage de type C #. J'ai trouvé une solution potentielle sur laquelle j'aimerais avoir votre avis. Je n'ai pas utilisé beaucoup de frameworks d'injection de dépendances donc il y a peut-être quelque chose que je néglige

Quoi qu'il en soit, l'idée est de pouvoir déclarer des propriétés "injectables" à l'aide d'un mot-clé. Lorsqu'un objet est instancié et que cette propriété n'est pas initialisée via le constructeur ou l'initialiseur d'objet, il demande une instance de ce type de propriété à un service global.

De même, vous enregistrez des gestionnaires pour différents types dans ce service afin de pouvoir instancier le type de propriété injecté.

L'avantage d'utiliser ce type d'architecture IMO est qu'il est assez flexible et facile à utiliser. L'inconvénient est qu'il peut y avoir un surcoût pour faire la légende au singleton chaque fois que vous lancez une classe qui a une injection.

Là encore, ce n'est qu'un problème pour les classes qui sont instanciées fréquemment dans une solution haute performance, donc cela ne devrait pas être un problème majeur. Vous pourriez peut-être utiliser une sorte d'usine dans ces cas.

Pensée, enjeux, questions, meilleures idées?

Code

public class SomeClass
{

  public SomeClass()
  {
     //implicit behavior if Animal is not set in constructor or initializer
    this.Animal =  GlobalInjector.Get(this,typeof(Mammal))

  }

  public injectable Mammal Animal  
  {
   get;
   set;
  }
}


 GlobalInjector.Register(typeof(Mammal), () => return new Mammal(someParameter));
Homde
la source
Pourriez-vous donner un exemple de pseudo-code pour ceux d'entre nous qui ne sont pas familiers avec DI? PS. Peut-être que vous pouvez aussi répondre à ma question concernant DI? :)
Steven
2
Je ne suis pas sûr de l'avoir compris. Vous pouvez obtenir tout cela avec un conteneur DI global et un attribut «[Injectable]» au lieu d'un mot clé, non?
nikie
Salut, j'ai essayé d'écrire un peu sur DI sur votre question, mais je ne suis pas sûr qu'elle y réponde
Homde
nikie: Oui bien sûr, je suppose que vous pouvez implémenter le mécanisme réel de différentes manières, je suis plus intéressé si la logique sous-jacente est saine
Homde
Alors, qu'est-ce qui est différent entre ceci et l'IoC existant autre que votre mot-clé supplémentaire?
Matthew Whited

Réponses:

7

Il y a des choses qui appartiennent aux langues et des choses qui ne le sont pas. Il y a longtemps, C a reconnu que les entrées-sorties n'appartenaient pas au langage car elles sont externes au modèle informatique et peuvent être implémentées avec des bibliothèques de fonctions.

L'injection de dépendance est comme ça. Il est externe au langage et peut être implémenté avec des cadres appropriés.

L'un des problèmes des langues modernes est qu'elles essaient d'en faire trop. Finalement, ces langages s'effondrent sous leur propre poids alors que les programmeurs fuient vers des langages plus simples.

Oncle Bob.
la source
Je suis d'accord en théorie, vous ne pouvez pas avoir un langage où chaque fonction est une caractéristique du langage sans qu'il soit gonflé. Cependant, il y a toujours de la place pour de nouvelles abstractions plus élevées qui nous aident à écrire un meilleur code. L'injection de dépendances n'est peut-être pas en soi le problème qui doit être résolu, mais le problème qu'il aborde, à savoir un moyen de nous faciliter la réduction des dépendances. Ce n'est peut-être pas la meilleure façon de le faire :)
Homde
5

Ce n'est pas nécessaire

L'une des choses que j'aime le plus dans les meilleurs frameworks DI que j'ai utilisés est que le code de configuration de niveau supérieur est la seule partie de votre code qui doit être informée sur DI. Le câblage automatique se fait au niveau du conteneur et de la configuration / "chargement du module", et votre code d'application peut en être complètement inconscient.

Cela signifie aucun attribut, aucune chaîne magique, aucune convention. Chaque morceau de code sait seulement qu'il accepte du code dans son constructeur (/ propriétés / méthodes), et c'est tout.

Avec un design comme celui-là, vous n'avez pas du tout besoin de modifier la langue pour prendre en charge l'injection de dépendance.

C'est potentiellement dangereux

Ce que je crains le plus à propos d'un système d'injection de dépendance intégré au langage, c'est qu'il soulèverait une barrière contre toute autre implémentation, mais il se peindrait probablement dans un coin à certains égards.

Certaines façons, il pourrait se peindre dans un coin:

  • Prise en charge uniquement de la configuration basée sur XML ou uniquement de la configuration basée sur du code
  • Ne pas pouvoir prendre en charge proprement le modèle de conception Factory (pas seulement les composants transitoires: composants générés au moment de l'exécution)
  • En quelque sorte, en changeant mon code, j'ai été obligé d'utiliser l'injection de dépendances et je ne pouvais pas simplement instancier ma classe pour les tests unitaires
  • Ne prend pas en charge les cycles de vie personnalisés
  • Ne pas être extensible
  • Ne pas être remplaçable dans les cas où j'ai besoin d'une plus grande personnalisation
  • Être brisé d'une manière que nous ne comprenons pas encore, parce que nous, utilisateurs de .Net, n'utilisons pas DI depuis assez longtemps pour connaître les pièges
Merlyn Morgan-Graham
la source
4

Avez-vous vu le Managed Extensibility Framework fourni avec .NET 4? Voici un article que j'ai écrit avec quelques exemples. Fondamentalement, il s'agit d'une forme d'injection de dépendances intégrée à .NET, avec les fonctionnalités supplémentaires de découverte au moment de l'exécution.

Les injections de propriétés ressemblent à ceci:

class Program
{
    [Import]
    public IMessageSender MessageSender { get; set; }
}

Les injections de constructeur ressemblent à ceci:

class Program
{
    [ImportingConstructor]
    public Program(IMessageSender messageSender) 
    {
    ...
    }
}

Vous pouvez importer des champs, effectuer une importation facultative, importer des collections de services, y compris l'importation paresseuse avec des métadonnées afin de rechercher un service approprié à instancier. Vous pouvez même réimporter au moment de l'exécution pour rechercher de nouvelles extensions.

Scott Whitlock
la source
Bien que MEF soit vraiment cool pour les plugins, je ne pense pas que je voudrais l'utiliser comme un mécanisme de DI général
Homde
1
@MKO - Pouvez-vous nous expliquer ce qui manque? Je connais tous les articles où Glenn Block se précipite pour rassurer les gens que MEF n'est pas là pour remplacer tous les cadres DI, mais si vous regardez les détails, il est évident que c'est plus une déclaration politique qu'autre chose. Cependant, si vous pouvez donner une bonne liste de fonctionnalités qui manquent à MEF par rapport à d'autres cadres DI, cela aidera les gens à prendre une décision éclairée. En outre, la question concerne les frameworks DI en C #, et MEF est clairement un conteneur DI dans le framework .NET.
Scott Whitlock
2
  1. Vous ne décrivez pas vraiment le mécanisme de configuration, qui à mon humble avis est le bit délicat. Comment faire pour que tout le code s'exécutant dans un thread utilise la connexion DB A, et tout le code dans l'autre connexion de thread B? Comment bloquez-vous l'injection d'une certaine ressource, car l'utilisateur actuellement connecté n'est pas autorisé à y accéder?
  2. N'utilisez pas d'injecteur global. N'utilisez aucune chose globale, ou vous pourriez aussi bien utiliser des variables globales. Non, l'utilisation du langage OOP comme singleton ou "statique" au lieu de global ne change pas leur nature globale.
  3. Prenons un conteneur à portée dynamique. Bien que la portée lexicale ait à juste titre gagné contre la portée dynamique, je pense que la portée dynamique ferait un bon remplacement pour la portée mondiale. L'héritage différentiel serait une bonne implémentation (comme dans l'héritage basé sur un prototype).
  4. Je crois qu'un mécanisme de DI mandaté par un langage devrait être vraiment simple, rien de tout cela qui est la norme en C # et en Java. Un mécanisme de cadrage dynamique avec une couche de configuration simple au-dessus pourrait faire l'affaire. Les solutions d'entreprise pourraient être superposées par des tiers.
Waquo
la source