[C#] Classes génériques, réflexion

Classes génériques, réflexion [C#] - C#/.NET managed - Programmation

Marsh Posté le 24-10-2009 à 01:08:36    

Bonjour a tous,
 
Je viens de tomber sur un problème assez important en commençant a toucher a la réflexion en C#, voici le contexte :
 
Le but de bout de code est de faire une interface de gestion des entrées / sorties de base (clavier, souris, manette ..).
Étant donne que ces 3 périphériques sont assez proches le code l'est aussi donc j'ai voulu utiliser un maximum de templates.
 
(Je développe sur XNA mais pour cet exemple j'ai fait sans).
 
J'ai donc 2 classes :
 
- LocalInputManager :
Se charge de stocker une liste de Control, de les modifier, supprimer, mettre en pause etc etc.
 
- Control :
Stock un groupe de touches liées a un évènements entre autre.
 
 
Voici un exemple :
 
LocalInputManager :  

Code :
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. namespace TestReflection
  6. {
  7.     public enum Keys
  8.     {
  9.         Left,
  10.         Right,
  11.         Up,
  12.         Down,
  13.         Space
  14.     };
  15.     class LocalInputManager<T, C> where C : class, new()
  16.     {
  17.         protected List<KeyValuePair<string, C>> controls;
  18.         private int totalControls;
  19.         public LocalInputManager()
  20.         {
  21.             this.totalControls = 0;
  22.             this.controls = new List<KeyValuePair<string, C>>();
  23.         }
  24.         public void AddControl(string Name, T Keys, bool KeyRepeat)
  25.         {
  26.             C instance = (C)Activator.CreateInstance(typeof(C), Keys, KeyRepeat);
  27.             this.controls.Add(new KeyValuePair<string, C>(Name, instance));
  28.             this.totalControls++;
  29.         }
  30.         public void UpdateAllControls()
  31.         {
  32.             for (int i = 0; i < this.totalControls; i++)
  33.             {
  34.                 this.controls[i].Value.Update();
  35.             }
  36.         }
  37.     }
  38. }


 
Control :  

Code :
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. namespace TestReflection
  6. {
  7.     class Control<T>
  8.     {
  9.         private T controls;
  10.         private bool repeat;
  11.         public Control()
  12.         {
  13.             this.repeat = false;
  14.         }
  15.         public Control(T Key, bool Repeat)
  16.         {
  17.             this.controls = Key;
  18.             this.repeat = Repeat;
  19.         }
  20.         public void Update()
  21.         {
  22.             Console.WriteLine("Mise a jour effectuee." );
  23.         }
  24.     }
  25. }


 
Et un petit main de test qui expose le probleme :

Code :
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. namespace TestReflection
  6. {
  7.     class Program
  8.     {
  9.         static void Main(string[] args)
  10.         {
  11.             LocalInputManager<Keys, Control<Keys>> manager;
  12.             manager = new LocalInputManager<Keys, Control<Keys>>();
  13.             manager.AddControl("Courir droite", Keys.Right, true);
  14.             manager.AddControl("Sauter", Keys.Space, false);
  15.         }
  16.     }
  17. }


 
Le problème se situe dans la classe LocalInputManager, dans la méthode UpdateAllControls.
En effet, il ne trouve pas la méthode Update() contenue dans C, ce en quoi j'ai du mal a lui en vouloir car C est un type générique.
 
Alors la question est : Comment lui préciser que C possède bel et bien la méthode sans préciser le type car il n'y a plus d'intérêt dans ce cas ?
 
Merci pour votre aide.


Message édité par Stnaire le 24-10-2009 à 01:09:08
Reply

Marsh Posté le 24-10-2009 à 01:08:36   

Reply

Marsh Posté le 24-10-2009 à 02:49:29    

Salut Fred82 et merci pour ta réponse rapide :)
 
Ton explication est claire et fonctionne parfaitement, un grand merci a toi.
 
En revanche j'avoue qu'il reste pour moi une zone d'ombre.
Je ne vois pas comment déclarer le constructeur de ma classe Control dans l'interface qui la décrit.
 
Je ne maitrise pas encore bien l'utilisation des interfaces mais étant donné qu'un constructeur prend le nom de sa classe je vois pas bien quoi mettre.
 
J'ai bien essaye INomInterface([...]); mais bon sans vraiment y croire car cela voudrait dire que je cherche a instancier l'interface :s
 
D'autant plus que ma classe Control est une classe template et qu'elle prend un type T en 1er paramètre d'un de ses constructeurs.
 
Le mot clef new sans déclaration supplémentaire ne me permet pas d'appeler autre chose que le constructeur par défaut, ce qui est assez logique.
 
Merci pour tes lumières :)
 
PS : Oui la puissance de ce langage m'impressionne beaucoup aussi.

Message cité 1 fois
Message édité par Stnaire le 24-10-2009 à 02:55:08
Reply

Marsh Posté le 25-10-2009 à 16:38:24    

Salut / re :s
 
Cette notation est très claire et agréable a l'œil, mais le seul truc qui me gêne, c'est les attributs en public en fait.

Reply

Marsh Posté le 26-10-2009 à 10:00:38    

Stnaire a écrit :

Salut / re :s
 
Cette notation est très claire et agréable a l'œil, mais le seul truc qui me gêne, c'est les attributs en public en fait.


 
Si tu veux qu'ils ne soient pas exposés en dehors de ton assembly, tu peux les passer en internal ce qui aura pour effet de ne les rendre visible uniquement à l'intérieur de ton assembly ou des autres assemblies qui seraient référencées en ShowInternalsTo dans le assemblyInfo.cs

Reply

Marsh Posté le 27-10-2009 à 20:15:55    

Tu te soucies un peu des perfs ?
A cet égard c'est très trèèèèès bien d'avoir pu virer la Reflection (merci la contrainte new() des generics... leur seul inconvénient c'est l'impossibilité d'utiliser un constructeur paramétré) mais ce pavé de generics et de classes abstraites c'est encore assez lourdingue.

 

J'ai l'impression que tu cherches à utiliser à fond les arcanes du langage faute d'en maitriser les bases... en témoigne ta premiere version qui utilisait la reflection.
J'ai un peu de mal à saisir l'ensemble des données du problèmes mais j'ai l'impression qu'avec une simple relation de polymorphisme tu pourrais alléger vachement ton implémentation.
Je n'ai pas essayé de recompiler ni rien mais à premiere vue je ne vois pas ce qui rend les generics indispensables, aussi bien C que T ?
Dans un cas tu as une classe abstraite, dans l'autre un type énuméré.

 

PS : simplement pour info, il est impossible de spécifier explicitement qu'un type generic est une énumération, mais tu peux lui imposer la contrainte "struct" qui limite déjà un peu les possibilités d'utilisation. Je trouve ça mieux que ne mettre aucune contrainte.

 

edit : et ta classe abstraite ne sert à rien on dirait, tu aurais pu utiliser une interface. Pour ce qui est de la visibilité des membres, avec les interfaces tu es contraint de tout mettre en public, ce qui est moche. Mais il y a une petite astuce (tjs pour info) : "implémenter l'interface explicitement" (je te laisse rechercher)


Message édité par TotalRecall le 27-10-2009 à 20:18:20

---------------
Topic .Net - C# @ Prog
Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed