Comment énumérer tous les éléments qui implémentent une interface générique?

J’ai deux interfaces, un générique et un non générique qui ont une hiérarchie d’inheritance:

public interface IGenericRelation : IRelation public interface IRelation 

Le générique est implémenté par plusieurs contrôles serveur chargés dynamicment et je souhaite énumérer l’ensemble des contrôles qui implémentent cette interface. Je peux faire ce qui suit

  foreach (IRelation relationControl in this.uiPlhControls.Controls.OfType<IRelation) { ... } 

Mais ce que j’aimerais vraiment pouvoir faire, c’est …

  foreach (IGenericRelation relationControl in this.uiPlhControls.Controls.OfType<IGenericRelation) { ... } 

et pouvoir ensuite utiliser le relationControl avec les types qu’il fournissait, car j’aurais alors access aux propriétés fortement typées disponibles sur IGenericRelation. Malheureusement, ce n’est pas possible car il semble que je ne peux pas omettre les parameters de type.

Est-ce que quelqu’un connaît un moyen d’énumérer les contrôles qui implémentent une interface générique pour m’empêcher d’écrire plusieurs boucles au lieu d’une? En utilisant la reflection peut-être?

Ce n’est pas possible, car IGenericRelation est un type complètement distinct de IGenericRelation . Si vous avez besoin d’accéder à des propriétés particulières communes à tous les IGenericRelation , vous devrez soit les implémenter au niveau de la couche IRelation , soit introduire une troisième interface entre IRelation et IGenericRelation<,> qui les implémentera. La raison en est que le compilateur ne dispose d’aucun moyen pour déduire quels types s’attendre à ce qu’il soit implémenté.

Le moyen le plus simple consiste à implémenter vos deux propriétés en tant object de niveau supérieur (soit IRelation soit une interface intermédiaire) fortement typé au niveau IGenericRelation<,> .

À quelles propriétés fortement typées essayez-vous d’accéder? S’ils sont fortement typés car ce sont les types d’entrée du générique, vous ne pourrez pas y accéder sans fournir les types dans votre boucle foreach. S’ils sont fortement typés, mais sans lien avec les types fournis, pouvez-vous les déplacer vers la classe IRelation?

Cela aura plus de sens avec un exemple de code – supposons que vos classes ressemblent à quelque chose comme:

 public IRelation { public ssortingng RelationshipType { get; set; } } public IGenericRelation : IRelation { public TParent Parent { get; set; } public TChild Child { get; set; } } 

Si votre liste contient une IGenericRelation IGenericRelation et une IGenericRelation vous ne pouvez pas les énumérer et les récupérer sans savoir quel type de béton vous recherchez:

 //Theoretical, non-compiling example.... foreach (IGenericRelation<,> relationControl in this.uiPlhControls.Controls.OfType>) { //This wouldn't work for type IGenericRelation relationControl.Parent.FooProperty = "Wibble"; //You would be able to access this, but there is no advantage over using IRelation relationControl.RelationshipType = "Wibble"; } 

(Notez que j’ai également dû changer le type de relationControl dans foreach à partir de votre exemple de code pour que l’utilisation possible ait un sens.)


Fondamentalement, il peut être utile de penser que les génériques .NET sont identiques aux classes basées sur un modèle C ++ (je sais que la mise en oeuvre est différente, mais l’effet à cet égard est le même). Imaginez qu’au moment de la compilation, tout votre code soit inspecté pour les utilisations de la classe IGenericRelation et que des classes concrètes non génériques soient créées en effectuant une recherche pour les mots clés TParent et TChild et en les remplaçant par le type demandé. Etant donné que les deux classes créées sont aussi distinctes que deux autres classes .NET, il est inutile de demander “toutes les classes qui ont commencé comme ce modèle”, le mieux que vous puissiez faire est de rechercher une classe ou une interface de base partagée (le cas échéant). IRelation.