Arbres en C#

Nous avons vu dans les pages précédentes que la réflexion permettait de manipuler les données d'un assembly. Nous pouvons utiliser ces données pour un explorateur de classes.

Comme un programme est constitué de classes, elles-mêmes constituées de constructeur(s), de méthodes, etc., nous allons en profiter pour utiliser les structures en arbre pour stocker ces données.

Nous allons utiliser un objet de la classe TreeNode, qui appartient à l'assembly System.Windows.Forms.


Code c# (trois racines) (8 lignes) :
  1. public static TreeNode[] getInfos(String classPath)
  2. {
  3. TreeNode classesTreeNode = new TreeNode("Classes");
  4. TreeNode enumsTreeNode = new TreeNode("Enums");
  5. TreeNode interfacesTreeNode = new TreeNode("Interfaces");
  6. TreeNode[] infos = { classesTreeNode, enumsTreeNode, interfacesTreeNode };
  7. return infos;
  8. }

Nous pouvons créer une classe qui contiendrait une méthode statique qui nous retourne un tableau contenant trois racines pour nos arbres.

Nous déclarons la classe avec l'accesseur public pour nous assurer que nous pouvons l'appeler depuis l'extérieur (en C#, l'accesseur par défaut est private).

Pourquoi avoir déclaré cette méthode statique ? Simplement pour ne pas nous obliger à instancier la classe (créer un objet de cette classe) quand nous désirons simplement utiliser les méthodes qu'elle nous propose.

Une méthode statique de la classe Assembly nous permet de charger par réflexion l'assembly dont nous passons le chemin en argument. Une fois notre objet de type Assembly instancié et initialisé, nous pouvons faire appel à une de ses méthodes qui nous retourne tous ses types. Nous pouvons donc parcourir en lecture la collection de types au moyen d'une boucle foreach. Au long de nos itérations, nous testons si le type correspond à un de nos types racine, et ci c'est le cas nous ajoutons le nom court du type dans le TreeNode correspondant.


Code c# (test du type) (16 lignes) :
  1. public static TreeNode[] getInfos(String classPath)
  2. {
  3. TreeNode classesTreeNode = new TreeNode("Classes");
  4. TreeNode enumsTreeNode = new TreeNode("Enums");
  5. TreeNode interfacesTreeNode = new TreeNode("Interfaces");
  6. Assembly assembly = Assembly.LoadFrom(classPath);
  7. Type[] types = assembly.GetTypes();
  8. foreach (Type type in types)
  9. {
  10. if (type.IsClass) classesTreeNode.Nodes.Add(type.Name);
  11. else if (type.IsEnum) enumsTreeNode.Nodes.Add(type.Name);
  12. else if (type.IsInterface) interfacesTreeNode.Nodes.Add(type.Name);
  13. }
  14. TreeNode[] infos = { classesTreeNode, enumsTreeNode, interfacesTreeNode };
  15. return infos;
  16. }

Nous pouvons aller plus loin, et créer une méthode qui nous retournera les noms des membres (méthodes, champs, ou propriétés) d'une classe.


Code c# (information sur la classe) (69 lignes) :
  1. public static TreeNode[] getInfos(String classPath)
  2. {
  3. TreeNode classesTreeNode = new TreeNode("Classes");
  4. TreeNode enumsTreeNode = new TreeNode("Enums");
  5. TreeNode interfacesTreeNode = new TreeNode("Interfaces");
  6. Assembly assembly = Assembly.LoadFrom(classPath);
  7. Type[] types = assembly.GetTypes();
  8. foreach (Type type in types)
  9. {
  10. if (type.IsClass) classesTreeNode.Nodes.Add(getClassNode(type));
  11. else if (type.IsEnum) enumsTreeNode.Nodes.Add(type.Name);
  12. else if (type.IsInterface) interfacesTreeNode.Nodes.Add(type.Name);
  13. }
  14. TreeNode[] infos = { classesTreeNode, enumsTreeNode, interfacesTreeNode };
  15. return infos;
  16. }
  17. private static TreeNode getClassNode(Type type)
  18. {
  19. TreeNode classNode = new TreeNode(type.Name);
  20. MethodInfo[] methodsInfos = type.GetMethods(
  21. BindingFlags.NonPublic |
  22. BindingFlags.Instance |
  23. BindingFlags.Public |
  24. BindingFlags.Static
  25. );
  26. TreeNode methodsNode = new TreeNode("Methods");
  27. foreach (MethodInfo methodInfo in methodsInfos)
  28. {
  29. methodsNode.Nodes.Add(methodInfo.Name);
  30. }
  31. classNode.Nodes.Add(methodsNode);
  32. ConstructorInfo[] constructorsInfos = type.GetConstructors(
  33. BindingFlags.NonPublic |
  34. BindingFlags.Instance |
  35. BindingFlags.Public |
  36. BindingFlags.Static
  37. );
  38. TreeNode constructorsNode = new TreeNode("Constructors");
  39. foreach (ConstructorInfo constructorInfo in constructorsInfos)
  40. {
  41. constructorsNode.Nodes.Add(constructorInfo.Name);
  42. }
  43. classNode.Nodes.Add(constructorsNode);
  44. FieldInfo[] fieldsInfos = type.GetFields(
  45. BindingFlags.NonPublic |
  46. BindingFlags.Instance |
  47. BindingFlags.Public |
  48. BindingFlags.Static
  49. );
  50. TreeNode fieldsNode = new TreeNode("Fields");
  51. foreach (FieldInfo fieldInfo in fieldsInfos)
  52. {
  53. fieldsNode.Nodes.Add(fieldInfo.Name);
  54. }
  55. classNode.Nodes.Add(fieldsNode);
  56. PropertyInfo[] propsInfos = type.GetProperties(
  57. BindingFlags.NonPublic |
  58. BindingFlags.Instance |
  59. BindingFlags.Public |
  60. BindingFlags.Static
  61. );
  62. TreeNode propsNode = new TreeNode("Properties");
  63. foreach (PropertyInfo propInfo in propsInfos)
  64. {
  65. propsNode.Nodes.Add(propInfo.Name);
  66. }
  67. classNode.Nodes.Add(propsNode);
  68. return classNode;
  69. }

Si nous le désirons, nous pouvons aussi récupérer tous les membres sans en connaître la nature, par la méthode GetMembers() de notre objet de la classe Type.

  1. public static TreeNode[] getInfos(String classPath)
  2. {
  3. TreeNode classesTreeNode = new TreeNode("Classes");
  4. TreeNode enumsTreeNode = new TreeNode("Enums");
  5. TreeNode interfacesTreeNode = new TreeNode("Interfaces");
  6. Assembly assembly = Assembly.LoadFrom(classPath);
  7. TreeNode[] infos = new TreeNode[assembly.GetTypes().Length];
  8. int infosIndex = 0;
  9. foreach (Type type in assembly.GetTypes())
  10. {
  11. TreeNode tmpTreeNode = new TreeNode(type.Name);
  12. foreach (MemberInfo memberInfo in type.GetMembers())
  13. {
  14. tmpTreeNode.Nodes.Add(memberInfo.Name);
  15. }
  16. infos[infosIndex++] = tmpTreeNode;
  17. }
  18. return infos;
  19. }

Mais retournons à nos moutons, ou plus précisément à nos classes. Nous pouvons affiner la granularité des informations en créant des méthodes particulières pour chaque catégorie de membre.

Nous allons aussi ajouter des tests pour signaler l'absence d'une catégorie de membres.

  1. using System;
  2. using System.Collections;
  3. using System.Text;
  4. using System.Reflection;
  5. using System.Windows.Forms;
  6. namespace ClassExplorer
  7. {
  8. class ClassInfo
  9. {
  10. public static TreeNode[] getInfos(String classPath)
  11. {
  12. TreeNode classesTreeNode = new TreeNode("Classes");
  13. TreeNode enumsTreeNode = new TreeNode("Enums");
  14. TreeNode interfacesTreeNode = new TreeNode("Interfaces");
  15. Assembly assembly = Assembly.LoadFrom(classPath);
  16. Type[] types = assembly.GetTypes();
  17. foreach (Type type in types)
  18. {
  19. if (type.IsClass) classesTreeNode.Nodes.Add(getClassNode(type));
  20. else if (type.IsEnum) enumsTreeNode.Nodes.Add(type.Name);
  21. else if (type.IsInterface) interfacesTreeNode.Nodes.Add(type.Name);
  22. }
  23. TreeNode[] infos = { classesTreeNode, enumsTreeNode, interfacesTreeNode };
  24. return infos;
  25. }
  26. private static TreeNode getClassNode(Type type)
  27. {
  28. TreeNode classNode = new TreeNode(type.Name);
  29. MethodInfo[] methodsInfos = type.GetMethods(
  30. BindingFlags.NonPublic |
  31. BindingFlags.Instance |
  32. BindingFlags.Public |
  33. BindingFlags.Static
  34. );
  35. if (methodsInfos.Length > 0)
  36. {
  37. TreeNode methodsNode = new TreeNode("Methods");
  38. foreach (MethodInfo methodInfo in methodsInfos)
  39. {
  40. methodsNode.Nodes.Add(getMethodNode(methodInfo));
  41. }
  42. classNode.Nodes.Add(methodsNode);
  43. }
  44. else classNode.Nodes.Add("No methods available");
  45. ConstructorInfo[] constructorsInfos = type.GetConstructors(
  46. BindingFlags.NonPublic |
  47. BindingFlags.Instance |
  48. BindingFlags.Public |
  49. BindingFlags.Static
  50. );
  51. if (constructorsInfos.Length > 0)
  52. {
  53. TreeNode constructorsNode = new TreeNode("Constructors");
  54. foreach (ConstructorInfo constructorInfo in constructorsInfos)
  55. {
  56. constructorsNode.Nodes.Add(getConstructorNode(constructorInfo));
  57. }
  58. classNode.Nodes.Add(constructorsNode);
  59. }
  60. else classNode.Nodes.Add("No constructors available");
  61. FieldInfo[] fieldsInfos = type.GetFields(
  62. BindingFlags.NonPublic |
  63. BindingFlags.Instance |
  64. BindingFlags.Public |
  65. BindingFlags.Static
  66. );
  67. if (fieldsInfos.Length > 0)
  68. {
  69. TreeNode fieldsNode = new TreeNode("Fields");
  70. foreach (FieldInfo fieldInfo in fieldsInfos)
  71. {
  72. fieldsNode.Nodes.Add(getFieldNode(fieldInfo));
  73. }
  74. classNode.Nodes.Add(fieldsNode);
  75. }
  76. else classNode.Nodes.Add("No fields available");
  77. PropertyInfo[] propsInfos = type.GetProperties(
  78. BindingFlags.NonPublic |
  79. BindingFlags.Instance |
  80. BindingFlags.Public |
  81. BindingFlags.Static
  82. );
  83. if (propsInfos.Length > 0)
  84. {
  85. TreeNode propsNode = new TreeNode("Properties");
  86. foreach (PropertyInfo propInfo in propsInfos)
  87. {
  88. propsNode.Nodes.Add(propInfo.Name);
  89. }
  90. classNode.Nodes.Add(propsNode);
  91. }
  92. else classNode.Nodes.Add("No properties available");
  93. return classNode;
  94. }
  95. private static TreeNode getConstructorNode(ConstructorInfo constructorInfo)
  96. {
  97. StringBuilder constrStr = new StringBuilder();
  98. if (constructorInfo.IsPrivate) constrStr.Append("Private ");
  99. else if (constructorInfo.IsStatic) constrStr.Append("Static ");
  100. else if (constructorInfo.IsPublic) constrStr.Append("Public ");
  101. constrStr.Append(constructorInfo.Name);
  102. TreeNode constructorNode = new TreeNode(constrStr.ToString());
  103. ParameterInfo[] paramInfos = constructorInfo.GetParameters();
  104. foreach (ParameterInfo paramInfo in paramInfos)
  105. {
  106. constructorNode.Nodes.Add(
  107. String.Format("{0} {1}", paramInfo.ParameterType.ToString(), paramInfo.Name)
  108. );
  109. }
  110. return constructorNode;
  111. }
  112. private static TreeNode getMethodNode(MethodInfo methodInfo)
  113. {
  114. StringBuilder methodStr = new StringBuilder();
  115. if (methodInfo.IsPrivate) methodStr.Append("Private ");
  116. else if (methodInfo.IsStatic) methodStr.Append("Static ");
  117. else if (methodInfo.IsPublic) methodStr.Append("Public ");
  118. methodStr.Append(methodInfo.Name);
  119. TreeNode methodNode = new TreeNode(methodStr.ToString());
  120. ParameterInfo[] paramInfos = methodInfo.GetParameters();
  121. foreach (ParameterInfo paramInfo in paramInfos)
  122. {
  123. methodNode.Nodes.Add(
  124. String.Format("{0} {1}", paramInfo.ParameterType.ToString(), paramInfo.Name)
  125. );
  126. }
  127. return methodNode;
  128. }
  129. private static TreeNode getFieldNode(FieldInfo fieldInfo)
  130. {
  131. StringBuilder fieldStr = new StringBuilder();
  132. if (fieldInfo.IsPrivate) fieldStr.Append("Private ");
  133. else if (fieldInfo.IsStatic) fieldStr.Append("Static ");
  134. else if (fieldInfo.IsPublic) fieldStr.Append("Public ");
  135. fieldStr.Append(fieldInfo.Name);
  136. TreeNode fieldNode = new TreeNode(fieldStr.ToString());
  137. return fieldNode;
  138. }
  139. }
  140. }

Nous pouvons encore améliorer notre code en n'affichant que les membres non hérités, en affichant le nombre de membres, etc. Nous verrons cela dans les pages suivantes, ainsi que le code nécessaire pour afficher nos arbres dans une console, ou dans un composant graphique.

Réseaux sociaux

Vous pouvez modifier vos préférences dans votre profil pour ne plus afficher les interactions avec les réseaux sociaux sur ces pages.

 

Nuage de mots clés

15 mots clés dont 0 définis manuellement (plus d'information...).

Avertissement

Cette page ne possède pas encore de mots clés manuels, ceci est donc un exemple automatique (les niveaux de pertinence sont fictifs, mais les liens sont valables). Pour tester le nuage avec une page qui contient des mots définis manuellement, vous pouvez cliquer ici.

Vous pouvez modifier vos préférences dans votre profil pour ne plus afficher le nuage de mots clés.

 

Astuce pour imprimer les couleurs des cellules de tableaux : http://www.gaudry.be/ast-rf-450.html
Aucun commentaire pour cette page

© Ce document issu de l′infobrol est enregistré sous le certificat Cyber PrInterDeposit Digital Numbertection. Enregistrement IDDN n° 5329-3671
Document créé le 29/09/06 01:19, dernière modification le Vendredi 17 Juin 2011, 12:11
Source du document imprimé : http:///www.gaudry.be/csharp-tree.html
St.Gaudry©07.01.02
Outils (masquer)
||
Recherche (afficher)
Recherche :

Utilisateur (masquer)
Apparence (afficher)
Stats (afficher)
15838 documents
455 astuces.
550 niouzes.
3107 definitions.
447 membres.
8121 messages.

Document genere en :
0,14 seconde

Mises à jour :
Mises à jour du site
Citation (masquer)
Les voyages sont l'éducation de la jeunesse et l'expérience de la vieillesse.

Francis Bacon
 
l'infobrol
Nous sommes le Mercredi 24 Mai 2017, 00:27, toutes les heures sont au format GMT+1.00 Heure, heure d'été (+1)