Cours VB.NET

Image non disponible


précédentsommairesuivant

V-X. Les génériques

Super complexe? non!!

V-X-1. Définition

A partir de VB 2005 on peut utiliser les génériques.

Un type générique (Generic) permet de créer une Classe ou une procédure, ayant des Data Types non définis au départ.

En d'autres termes, les paramètres et variables n'ont pas de type: ce ne sont pas des Strings, des Integers.. Ce sont des génériques. Quand on utilise la Classe ou la procédure, on indique le type.

Les génériques nous permettent de définir un comportement ou un algorithme commun sur les types ou un sous ensemble de types .Net. Ils sont un moyen de mutualiser un comportement.

Par exemple, je vais écrire une routine de calcul avec des génériques, elle sera utilisable avec des Integers, des Singles..

Exemple de Fonction utilisant un 'generic'.

Permettant d'en comprendre l'intérêt:

Créons une sub nommée Swap ( elle sert à intervertir 2 variables) fonctionnant pour tous les types de données:

 
Sélectionnez

Private Sub Swap(Of ItemType) (ByRef v1 As ItemType, ByRef v2 As ItemType)

Dim temp As ItemType

temp = v1

v1 = v2

v2 = temp

End Sub

Notons que en plus des 2 paramètres v1 et v2 à 'swapper' ,"Of ItemType" indique le type de donnée qui doit être utilisé.

Si on a 2 entiers à swapper, il faut appeler la fonction Swap comme cela:

 
Sélectionnez

Swap(Of Integer)(v1, v2)

Si ce sont des Strings:

 
Sélectionnez

Swap(Of String)(v1, v2)

Le JIT compile la fonction Swap comme si elle avait été écrite pour des Strings.

Sans les génériques j'aurais fait plusieurs routines de code pour chaque Type. Or en utilisant les génériques cette redondance peut être évitée.

Exemple de Classe utilisant un 'generic'. A revoir quand vous connaîtrez les classes.

De la même manière, on peut créer une Classe entièrement générique:

 
Sélectionnez

Public Class SomeClass(Of ItemType)

Private internalVar as ItemType    ' variable generic

Public Function SomeMethod(ByVal value As ItemType) As ItemType

'Fonction acceptant un generic comme paramètre
...
End Function

End Class

Exemple de Collection utilisant un 'generic'.

On peut créer une collection générique (System.Collections.Generic) et lui imposer un type.

Exemple: créons une collection de String : List(Of String).

 
Sélectionnez

Imports System.Collections.Generic.



Dim l As New List(Of String)

l.Add("toto")    'On ajoute une string

Dim S As String = l.Item(0) ' l'item est bien typé : même avec 'Option Strict=on' 
'pas besoin de CType. 

Habituellement les collections contiennent des objets; ici c'est une collection de String.

Je ne peux y mettre que des String (sinon cela provoque une erreur).

Comme par définition c'est des string, il n'y a pas de conversion String=>Objet et Objet=>String (pas de boxing/unboxing)

On peut aussi créer des Stack(Of..) Queue(Of..), Dictionnary(Of..) SortedList(Of..)..

V-X-2. Intérêts des génériques ?

Pourquoi ne pas utiliser des types 'Object' à la place des génériques?

Les génériques sont fortement typés. Si on crée une collection générique de Long, on ne peut utiliser que des Long: c'est mieux, cela évite les erreurs, les conversions de type.

Ils sont plus rapides que l'usage des objets.

S'il y a erreur, elle se produit probablement à la compilation et pas à l'exécution.

Cela permet d'utiliser l'intellisense.

Comparaison ArrayList (non générique) et List (Of) générique. Si on utilise une ArrayList qui est une liste non générique, on peut sans problèmes ajouter un Integer puis une String: cela n'est pas logique et possiblement une erreur.
De plus quand on travaille sur cette liste ou qu'on parcourt cette liste il y a des opérations de Cast et de boxing/unboxing sans arrèts: on stocke des Integer, String dans des objets.
Par contre si on utilise une List générique typée, pas de Cast ni de boxing (rapidité++) et reduction du nombre d'erreur possible: une List de String ne peut contenir que des String.

V-X-3. Usage des génériques

On peut utiliser des méthodes génériques pour travailler sur les tableaux.

Exemple recherche dans un tableau de short nommé monTab l'élément 2

 
Sélectionnez

index= Array.indexOf (Of Short)(monTab, 2) 

est hyper plus rapide que

index= Array.indexOf (monTab, 2) car la première version avec généric est directement optimisée pour les Short.

Il est de même pour Binarysearch et Sort.

Cela est valable pour les types 'valeur' (peu d'intérêts pour les strings par exemple).

Collections génériques:

On peut créer une collection générique (System.Collections.Generic) et lui imposer un type.

Exemple: créons une collection de String (List(Of String)): Elle est typée car elle ne peut contenir que des 'String'.

 
Sélectionnez

Dim l As New List(Of String)

Il s'agit d'une List avec Index.

l.Add("toto")    'On ajoute une string

Dim S As String = l.Item(0) ' l'item est bien typé : même avec 'Option Strict=on' 
'pas besoin de CType. 

Il y a aussi de nouveaux types de collections génériques

-Les Dictionnary(Of..) avec Clé et valeur

-Les SortedDictionnary(Of..) avec Clé et valeur trié.

-Les LinkedList(Of..) Liste Chaînée, chaque élément comportant une propriété Value, Next et Previous.

-Les SortedList(Of..)..

-Les Stack(Of..)

-Les Queue(Of..)

On peut aussi créer des collections 'composées'.

 
Sélectionnez

Dim genericColl As New Dictionary(Of String, String)
genericColl.Add("PremiereClé", item1)

V-Y. Linq

'Language-Integrated Query' (LINQ), veut dire "langage de requête intégré".

On l'utilise dans VB à partir de VB2008 (Framework 3.5).

V-Y-1. Définition, mise en place

C'est un langage de requêtes (permettant d'interroger une source de données) directement dans le code Visual Basic et à l'aide de mots clés familiers (issues du SQL, le langage d'interrogation des bases de données).

Cette source de données peut être une Base de données (Linq To SQL et Linq To DataSet )un fichier XML (Link To XML) mais aussi une collection, un tableau, une chaîne de caractères.

On parle dans ce dernier cas de 'Linq To Objects'. Si un objet prend en charge l'interface IEnumerable ou IEnumerable (Of), le fournisseur LINQ to Objects vous permet de l'interroger.

LINQ (dixit Microsoft) offrent trois principaux avantages par rapport aux boucles for Each traditionnelles :

Les requêtes:

-Elles sont plus concises et lisibles, surtout lors du filtrage de plusieurs conditions.

-Elles fournissent des fonctions puissantes de filtrage, de classement et de regroupement avec un minimum de code d'application.

-Elles peuvent être appliquées à d'autres sources de données avec peu ou pas de changement.

Pour que LINQ soit pris en compte il faut:

Utiliser VB 2008 et le framework 3.5.

Dans les propriétés, onglet compile, il faut que Option Infer=On

Il faut ajouter System.Data.Linq:

Si vous créez un nouveau projet dans VB 2008, toutes les conditions sont effectives par défaut, si vous modifiez un ancien projet, il faut rajouter certaines références:

Dans l'Explorateur de solutions (Projet, Propriétés..), cliquez sur Références, puis cliquez sur Ajouter une référence.

Cliquez sur .NET, sur l'assembly System.Data.Linq, puis sur OK, cela ajoute la référence.

Image non disponible

Il faut ajouter l'espace de nom:

Dans l'explorateur de solution cocher Systel.Data.Link comme ci-dessus
ou ajouter les directives suivantes en haut du Module1 :Imports System.Data.Linq

V-Y-2. Principe d'une requête Linq

A titre d'exemple simpliste, on a des données dans MyData et chaque donnée a les champs 'Nom', "Prenom", "Ville"... Comment chercher les enregistrements ayant comme nom "toto"?

 
Sélectionnez

Dim Resultat = From Element In MyData _

Where Element.Nom = "Toto" _

Select Element

On crée une variable de requête (ici ' Dim Resultat') qui sera chargée de contenir la requête (et pas les résultats),

puis l'expression de requête composée de:

From : dans quoi chercher? dans quel élément?

In : quelle source de données? dans MyData.

Where : précise les conditions à appliquer, c'est le 'filtre'.

Select: Précise les éléments à extraire qui vont apparaître dans 'Resultat'

Remarquons que Dim From In Where Select doivent être sur une seule unique et même ligne; pour la lisibilité, on écrit sur plusieurs lignes en ajoutant des continuateurs de lignes " _".

Remarquons aussi qu'initialement on connaît MyData et on sait que chaque élément de MyData a un champ 'Nom', c'est tout!! On utilise dans la requête les nouvelles variables 'Resultat' et 'Element' sans avoir à déclarer leurs types (on aurait pu le faire). 'Element' est une variable de portée déduite comme élément de MyData.

Ce fonctionnement particulier de LINQ est possible grâce à l'inférence de type et aux types anonymes (voir plus bas).

Et pour afficher les noms dans une ListBox:

 
Sélectionnez

For Each P In Resultat

   ListBox1.Items.Add(P.NOM )

Next

Ici la requête contenue dans la variable de requête 'Resultat' est exécutée pour 'alimenter' la boucle 'For Each'.
On remarque donc que l'exécution est différée.

On peut 'forcer' l'exécution immédiate en mettant la requête entre parenthèses et en utilisant une propriété (.Count , .ToArray, .ToList ):

 
Sélectionnez

' Execution immédiate avec ToList.
Dim ListPersonneAyantPrenomToto = (From Element In MyData _
Where Element.Nom = "Toto" _
Select Element).ToList()
' On retrouve la liste des eléments de MyData ayant le Prenom='Toto"

' Execution immédiate avec Count.
Dim NombrePersonneAyantPrenomToto = (From Element In MyData _
Where Element.Nom = "Toto").Count()
' On a compté le nombre d'élément ayant  pour Prenom="Toto".
'NombrePersonneAyantPrenomToto contient le résultat

On peut aussi utiliser .ToList ou .ToArray en mode différé:

 
Sélectionnez

' Execution différée .
Dim Resultat = From Element In MyData _
Where Element.Nom = "Toto" _
Select Element
' . . .
Dim Tableau = Resultat.ToArray()

Order By permet de trier les résultats.

 
Sélectionnez

Dim Resultat = From Element In MyData _

 Order By Element.Price Descending, Element.Nom _

 Select Element.Nom, Element.Price

Ici on trie par prix décroissant, puis à prix égal sur le nom croissant.

Remarquons qu'on sélectionne seulement 2 'colonnes'.

Il est possible d'avoir plusieurs sources, dans ce cas chaque bloc .In est séparé par une virgule:

 
Sélectionnez

Dim queryResults = From cust In customers, ord In orders _
                   Where cust.CustomerID = ord.CustomerID _
                   Select cust, ord

La clause Where peut contenir des conditions complexes avec des AND des OR..

 
Sélectionnez


Dim custs = From cust In db.Customers _
            Where cust.Country = "France" _
                And (cust.CompanyName.StartsWith("F") _
                Or cust.CompanyName.StartsWith("V")) _
            Order By cust.CompanyName _
            Select cust.CompanyName, cust.City

DataGridView1.DataSource = custs

V-Y-3. Link et les tableaux d'Integers

Un tableau peut être interrogé par Linq.

Exemple: rechercher les nombres pairs dans un tableau d'Integer :

 
Sélectionnez

' La Data source: c'est un tableau d'Integer 

Dim numbers() As Integer = {0, 1, 2, 3, 4, 5, 6}

 

' Création de la requête.

'Pour chaque élément num dans la source

'Si l'élément num est tel que num Mod 2=0 (condition pour qu'il soit pair)

'Selectionner num et le mettre dans réponses

 Dim réponses = From num In numbers _

                 Where num Mod 2 = 0  _

                 Select num 

 

' Exécution de la requête. 

' On utilise les réponses

For Each number In réponses 

    Console.Write(number & " ")

Next

Cela affiche sur la console(menu Affichage puis Sortie): 0 2 4 6

On peut vouloir compter uniquement les nombres pairs:

 
Sélectionnez

Dim nombredepair = (From num In numbers _ 

                    Where num Mod 2 = 0 _ 

                    Select num).Count()

Console.Write(nombrepair) 'pour afficher 4

On remarque que dans le premier exemple (Select num) l'exécution de la requête est effectuée au cours de la boucle For Each (exécution différée par rapport à la création) alors que dans le second exemple (count) , l'exécution est immédiate.

V-Y-4. Link et les chaînes de caractères

Soit une chaîne de caractères MyString, rechercher les caractères qui sont des nombres.

 
Sélectionnez

' Un string 

Dim MyString As String = "ABCjkjhkhs666KMOOP"

' Select les caractères qui sont des nombres
Dim Query = From ch In MyString _
Where ch.IsDigit(ch) _
Select ch


' Exécution de la requête
For Each c As Char In Query
  Console.Write(c & " ")
Next

' Combien y a t-il de nombres?
Dim count As Integer = Query.Count()
Console.WriteLine("Count = " & count)

On remarque qu'il n'est pas nécessaire de réexecuter la requête.

Autre syntaxe:
Sélectionner tous les caractères avant '6'

 
Sélectionnez

Dim Query2 = MyString.TakeWhile(Function(c) c <> "6")

' Execute the second query
For Each ch In Query2
 Console.Write(ch)
Next

Ici on a utilisé TakeWhile qui sélectionne les caractères jusqu'à 6. (les sélectionne une seule fois). On a utilisé une expression lambda (voir le chapitre sur les expressions lambdas).

 
Sélectionnez

Dim Query2 = MyString.Except("6")

Ici on a utilisé Except qui sélectionne les caractères sauf 6.

V-Y-5. Link et les mots d'une chaîne de caractères

Rechercher combien de fois une String contient le mot 'Basic':

 
Sélectionnez

Dim text As String = "Ceci est un cours Visual Basic" & _
" pour les débutants et les autres"

Dim searchTerm As String = "Basic"

' Conversion de la String en Tableau de mots:.
Dim dataSource As String() = text.Split(New Char() {" ", ",", ".", ";", ":"}, _
StringSplitOptions.RemoveEmptyEntries)

' Création et exécution de la requête
' Utiliser ToLower pour  trouver "Basic " et "Basic" 
Dim Query = From word In dataSource _
Where word.ToLowerInvariant() = searchTerm.ToLowerInvariant() _
Select word

' Compter les 'Basic'.
Dim count As Integer = Query.Count()
Console.WriteLine(count )

V-Y-6. Link pour rechercher la différence entre deux listes de noms

Rechercher dans la String nom1, les noms qui ne sont pas aussi dans nom2.

 
Sélectionnez

' Soit 2 tableaux de Sting 
Dim nom1 As String() =  {"Philippe", "Paul"}
Dim nom2 As String() = {"Paul", "Jean"}




' Créer la requête.
Dim difference = nom1.Except(nom2)



' Executer
For Each name As String In difference
 Console.WriteLine(name)
Next

Affiche 'Philippe'

V-Y-7. Link et les contrôles

Comment obtenir la liste des contrôles actifs dans un formulaire?

 
Sélectionnez

Dim ControlsEnabled = _
            From c In Me.Controls _
            Where CType(c, Control).Enabled _
            Select CType(c, Control)

On se rend bien compte que, ici, Linq est une alternative à For Each.

V-Y-8. Inference de Type et type anonyme

Débutant, tu peux sauter!!

On a vu que Linq fonctionnait d'une manière un peu particulière. Pour mieux comprendre cela, il faut savoir qu'à partir de VB 2008 on peut utiliser l'inférence de type et les types anonymes.

Inférence de Type

Il faut pour cela que Option Infer =On (Off par défaut)

Passer par le menu 'Projet' puis 'Propriétés de..', onglet 'Compiler'

En plus des options Explicit, Compare, Strict, on peut modifier Option Infer.

L'inférence est la capacité de déduire le type d'une variable par analyse des types fournis en entrées ainsi que des opérations effectuées sur ceux-ci. C'est donc le compilateur qui déduit le type de la variable.

 
Sélectionnez

' Type explicite pour une String
Dim Myname1 As String = "Rouge"

' Exploitation de l'inférence de type
Dim Myname2 = "Vert"

Le passage du curseur de la souris sur Myname2 vous permet de découvrir que celui-ci est bien un type "String".

On avait dit qu'il fallait travailler avec Option Implicit = True et là on ne déclare même pas le type!!! En fait l'inférence existe afin de supporter par exemple les types anonymes ou encore LINQ.

Il existe des cas pour lesquels l'inférence de type ne se produit pas. Pour les instructions Dim locales, l'inférence de type survient uniquement lorsqu'il y a une assignation sur la ligne de déclaration. Par conséquent, pour les assignations effectuées hors de la déclaration de la variable, le compilateur supposera que le type est Object. Object est également toujours déduit comme type des membres de niveau classe, si bien que l'inférence de type ne s'applique pas aux fonctions, sous-routines, propriétés, champs de classe/structure, etc Lorsque Option Explicit est Off , une variable locale peut être utilisée dans le code sans déclaration explicite. La variable est supposée être dans ce cas de type Object et tous les appels sont liés tardivement. L'inférence de type ne survient pas sur les variables définies implicitement.

Type anonyme

Habituellement, on peut déclarer Mycustomer, une instance de la classe Customer et renseigner une propriété .Name.

 
Sélectionnez

Dim MyCustomer = New Customer With {.Name = "Philippe"}

Grâce au type anonyme, on peut écrire:

 
Sélectionnez

Dim AnomyneCustomer = New With {.Name = "Philippe"}

Remarque= avant New il doit y avoir '=' et pas As.

Cela créer une nouvelle classe anonyme (sans nom) possédant une propriété .Name.

Les types anonymes sont surtout utilisés avec Linq:

Exemple:

 
Sélectionnez

Dim namePriceQuery = From prod In products _ 

                     Select prod.Name, prod.Price

Si products est une liste d'objets avec plein de propriétés, namePriceQuery est une collection de type anonyme qui posséde 2 propriétés: .Name et .Price .

V-Z. Les 'Region', compilation conditionnelle, 'Attributs'

Dans le code on peut ajouter des choses qui ne sont pas du code VB, mais plutôt des directives pour l'affichage, le compilateur ou le Runtime:

V-Z-1. Les Régions

Pour une meilleure visibilité, il est possible de créer des 'régions' de code. Une région peut être déroulée ou contractée.

Une région peut être déroulée: le code entre #Region et #End Region est visible (pour modifier le code par exemple):

-

#Region "Routine de Tri"

 
Sélectionnez

Sub QuickSort(ByVal debut As Integer, ByVal fin As Integer)

Dim pivot, gauche, droite, temp As Integer

Do

...

Loop Until gauche = droite

End Sub

#End Region

Si on clique sur le petit carré (avant #region), cela contracte la région et masque le code, on voit seulement un petit carré avec un plus et le nom de la région.

+ Routine de Tri

Cela permet de masquer une procédure en totalité.

Attention, cela ne permet pas de masquer seulement une partie du code mais la procédure entière.

Exemple:

En VB 2003, dans une Classe de formulaire, il existe une région nommée 'Code généré par le Concepteur Windows Form' qui contient le code créant les contrôles du formulaire. Ce code est habituellement caché dans une 'région' fermée.

V-Z-2. La Compilation conditionnelle

La compilation conditionnelle contrôle si les séquences de lignes sont traduites en code réel. Certaines lignes peuvent être ignorées pendant le processus de compilation.

Les instructions de compilation conditionnelle sont précédées de #

On utilise:

 
Sélectionnez


#if .. then

#else

#end if

Exemple

 
Sélectionnez

#const Demo = True    'créer une constante conditionnelle

Class MaClasse
#if Demo then
  Sub F()
#else
  Sub G()
#end if

End Class

La compilation produit le résultat suivant :

 
Sélectionnez

Class C
Sub F()
End Class

Il suffit de changer la valeur de la constante pour compiler des parties différentes de code.

Noter que #const Demo crée une constante privée accessible uniquement dans le fichier.

En VB 2005 on peut définir une constante au niveau projet avec /define

 
Sélectionnez

/define const Demo=True

V-Z-3. Les Attributs

Les attributs peuvent être utilisés pour décrire votre code au runtime (fournir des informations supplémentaires) ou modifier le comportement de l'application au moment de l'exécution. Le Framework fournit de nombreux attributs , mais vous pouvez également créer vos propres attributs personnalisés.

Les attributs sont entre < et > en VisualBasic.

Les attributs peuvent modifier le comportement des propriétés, méthodes, classes, assemblys. Ils couvrent différents aspects comme la compilation, la sécurité, les services Web...

Exemple: <Obsolete > Avec une procédure.

Déclarons une fonction Add comme obsolète, en plus, le compilateur affiche le message: 'Sera enlevé à la prochaine version'.

On utilise donc <Obsolete > ou le nom complet de l'attribut: <System.ObsoleteAttribut>

 
Sélectionnez

<Obsolete("Sera enlevé à la prochaine version ")> Function Add(a as Integer, b as Integer) as Integer
Add = a + b - c
End Function

Exemple:<Browsable> avec un composant.

Dans un composant, je crée une Propertie nommée 'Valide', je ne veux pas qu'elle apparaisse dans la fenêtre 'propriétés' du composant; je veux qu'elle soit accessible uniquement par code:

 
Sélectionnez


Imports System.ComponentModel    'Classe chargées du comportement des composants.

 

<Browsable(False)> Property Valide() As Integer

Exemple:<ToolBoxBitMap> avec un composant.

Quand on crée un composant, on désire parfois avoir une icône propre à ce composant dans la boite à outils:

 
Sélectionnez

<ToolBoxBitMap("C:MonIcone")> Public Class MaClasse

Exemple:<Serializable> avec une Classe.

Quand on crée une classe, on a parfois besoin qu'elle soit sérializable:

 
Sélectionnez

<Serializable()> Public Class TestSimpleObject

Public member1 As Integer
Public member2 As String
Public member3 As String
Public member4 As Double

'Un member qui ne doit pas être sérialisé.
<NonSerialized()> Public member5 As String

Il est possible de faire un tas de choses avec les attributs, mais cela devient vite très complexe.

V-AA. Traiter les erreurs

Image non disponible

Il y a plusieurs types d'erreurs.

- Les erreurs de syntaxe.

- Les erreurs d'exécution.

- Les erreurs de logique.

Image non disponibleVoir la vidéo : au format 'Flash'> ou au format 'Avi' en Visual Basic 2005.

V-AA-1. Les erreurs de syntaxe

On peut aussi les nommer 'les erreurs du compilateur', elles se produisent lorsque le compilateur Visual Basic rencontre un code non reconnaissable, erreur de saisie ou méconnaissance du langage. Comme les erreurs du compilateur empêchent un programme de s'exécuter, vous devez être averti de ces erreurs avant de tenter d'exécuter votre programme, autrement dit durant la saisie du code.

Elles surviennent donc en mode conception quand on tape le code:

Exemples:

 
Sélectionnez

A+1=B            'Erreur dans l'affectation

f.ShowDialogue   'Faute de frappe, il fallait taper ShowDialog

2 For... et un seul Next

Dim i As Integer: Label.Text= i  'Affectation d'un Integer à une propriété text qui attend une String.

....

Dans ces cas VB souligne en ondulé bleu le code. Il faut mettre le curseur sur le mot souligné, l'explication de l'erreur apparaît.

Exemple: Propriété Text d'un label mal orthographiée:

Image non disponible

Il faut les corriger immédiatement en tapant le bon code (ici 'Text').

En bas il y a aussi une fenêtre; "liste des erreurs":

Image non disponible

Elle affiche tous les problèmes; pour atteindre le code correspondant à une de ces erreurs, double-cliquez sur une des lignes de la liste.

En VB 2005 un bouton avec point d'exclamation permet d'ouvrir une fenêtre proposant le moyen de corriger l'erreur:

Image non disponible

Ici on met dans la propriété text d'un label un Integer, alors qu'il faut mettre une String (Option Strict est probablement égal à On); Vb montre la correction : CStr(i) converti i en String.

Si vous exécutez le programme dans l'IDE alors qu' il y a un problème, VB demande si on veut exécuter la dernière génération réussie:

Image non disponible

Si vous tapez 'oui' VB exécute la dernière version qui a été générée correctement, mais PAS le code source actuel qui contient des erreurs!!

V-AA-2. Les erreurs d'exécution

Elles surviennent en mode Run dans l'IDE ou lors de l'utilisation de l'exécutable:
Une instruction ne peut pas être effectuée.

Quand on utilise l'exécutable: Le logiciel s'arrête brutalement, c'est très gênant!!

Pour l'utilisateur c'est un 'BUG' Image non disponible

Il y a 'levée d'une exception', voila ce que cela donne dans l'IDE:

Exemple: je tente d'accéder à un élément d'un tableau qui n'existe pas (l'indice est trop grand cela entraîne une exception 'OutOfRange').

En cours de test, dans l'IDE, s'il y a une exception, le logiciel s'arrête, l'instruction qui a planté apparaît en jaune et VB donne une explication.

Image non disponible
L'erreur est:
  • Soit une erreur de conception.

    Exemple:

    Ouvrir un fichier qui n'existe pas (On aurait du vérifier qu'il existe avant de l'ouvrir!).

    Division par zéro.

    Utiliser un index d'élément de tableau supérieur au nombre d'élément:

    Envoyer un mauvais paramètre à une fonction.

  • Soit une erreur de l'utilisateur.

    Exemple: On lui demande de taper un chiffre, il tape une lettre ou rien puis valide.

    Il faut toujours vérifier ce que fait l'utilisateur et prévoir toutes les possibilités.

    Exemple: si je demande à l'utilisateur de taper un nombre entre 1 et 10, il faut:

    Vérifier qu'il a tapé quelque chose.

    Que c'est bien un chiffre (pas des lettres).

    Que le chiffre est bien entre 1 et 10.

    Sinon il faudra reposer la question.

A-Capter les erreurs avec Try Catch Finally:

Plutôt que de laisser le logiciel 'planter', je vais anticiper et essayer de capter l'erreur au niveau des lignes de code qui peuvent la provoquer.

Avant l'instruction supposée provoquer une erreur indiquez: Essayer l'instruction (Try), si une erreur se produit Intercepter l'erreur (Catch) puis poursuivre (après Finally).

 
Sélectionnez

Try

    'Instruction susceptible de provoquer une erreur.

Catch

    'Traitement de l'erreur

Finally

    'Code toujours exécuté    

End Try

Il faut pour que cela fonctionne avoir tapé au préalable Imports System.IO

Il est possible d'utiliser Catch pour récupérer l'objet 'Exception' qui est généré par l'erreur.

 
Sélectionnez

Catch ex As Exception

Cet objet Exception à des propriétés:

Message qui contient le descriptif de l'erreur.

Source qui contient l'objet qui a provoqué l'erreur....

ex.Message contient donc le message de l'erreur.

Cet objet généraliste Exception( de l'espace IO) a aussi des classes dérivées:

-StackOverFlowException

-FileNotFoundException

-EndOfStreamException

-FileLoadException

-PathTooLongException.

Enfin une exception peut provenir de l'espace System: ArgumentExceptions; ArithmeticException:

-DivideByZeroException.....

Il est possible d'écrire plusieurs instructions Catch avec pour chacune le type de l'erreur à intercepter. (Faisant partie de la classe Exceptions)

Exemple:

On ouvre un fichier par StreamReader , comment intercepter les exceptions suivantes?

Répertoire non valide

Fichier non valide

Autre.

 
Sélectionnez

Try

    sr= New StreamerReader (NomFichier)

Catch ex As DirectoryNotFoundException

    MsgBox("Répertoire invalide")

Catch ex As FileNotFoundException

    MsgBox("Fichier invalide")

Catch ex As Exception

    MsgBox(ex.Message)

End Try

Noter que le dernier Catch intercepte toutes les autres exceptions.

On peut encore affiner la gestion par le mot clé When qui permet une condition.

 
Sélectionnez

Catch ex As FileNotFoundException

             When ex.Message.IndexOf ("Mon Fichier.txt") >0

                MsgBox ("Impossible d'ouvrir Mon Fichier.txt")

Si le texte "Mon Fichier.txt" est dans le message, affichez que c'est lui qui ne peut pas être ouvert.

Exit Try permet de sortir prématurément. Quitte immédiatement le bloc Try ou Catch dans lequel il est. L'exécution continue avec le bloc Finally s'il y en a un, ou avec l'instruction qui suit End Try.

B-Capter les erreurs avec On error :

On peut aussi utiliser la méthode Visual Basic:

On Error Goto permet en cas d'erreur de sauter à une étiquette (un emplacement dans le code) emplacement ou une portion de code traite l'erreur.

On peut lire le numéro de l'erreur qui s'est produite, ce numéro est dans Err.Number.

Err.Description contient le texte décrivant l'erreur. Err.Source donne le nom de l'objet ou de l'application qui a crée l'erreur.

Quand l'erreur est corrigée, on peut revenir de nouveau à la ligne qui a provoqué l'erreur grâce à Resume ou poursuivre à la ligne suivante grâce à Resume Next

Exemple:

 
Sélectionnez

On Error GoTo RoutinedErreur 'Si une erreur se produit se rendre à 'RoutineErreur'
Dim x As Integer = 33
Dim y As Integer = 0
Dim z As Integer
z = x / y ' Crée une division par 0 !!

RoutinedErreur: ' La Routine d'erreur est ici (remarquer  ':' indiquant une etiquette).
Select Case Err.Number ' On regarde le numéro de l'erreur.
Case 6 ' Cas : Division par zéro interdite
    y = 1 ' corrige l'erreur.
Case Else
    ' autres erreurs....
End Select
Resume ' Retour à la ligne qui a provoqué l'erreur.

Pour arrêter la gestion des erreurs il faut utiliser:

 
Sélectionnez

On Error Goto 0

Parfois on utilise une gestion hyper simplifiée des erreurs:

Si une instruction 'plante', la sauter et passer à l'instruction suivante, pour cela on utilise:

On Error Resume Next

Exemple: On veut effacer un fichier

 
Sélectionnez

On Error Resume Next

Kill (MonFichier)

On Error goto 0

Ainsi , si le fichier n'existe pas , cela ne plante pas (on aurait pu aussi vérifier qu'il existe avant de l'effacer!!).

On Error Gosub n'existe plus.

On Error est moins performant que Try Catch et surtout il ralentit le code+++: si nécessaire utiliser Try Catch.

En résumé: pour éviter les erreurs d'exécution il est donc possible:

- D'écrire du code gérant le problème, contrôlant les actions de l'utilisateur..

Exemple: on demande à l'utilisateur de saisir un nombre dans TextBox1 puis de cliquer sur Button3

Si l'utilisateur a tapé une lettre au lieu d'un chiffre, le prévenir.

 
Sélectionnez

Private Sub Button3_Click 

If String.IsNullOrEmpty(TextBox1.Text) Then 'on teste si l'utilisateur a tapé quelque chose

 MsgBox("Tapez quelque chose")

Else

 If Not IsNumeric(TextBox1.Text) Then 'on teste si l'utilisateur a tapé du numérique

    MsgBox("Tapez un chiffre")

 End If

End If

End Sub

- Une autre alternative est de capter l'erreur.

Exemple: on demande à l'utilisateur de saisir un nombre dans TextBox1 puis de cliquez sur Button3

Convertir le texte tapé en Integer, on sait que si la conversion est impossible (pas de texte tapé ou texte non numérique) une exception invalidCastException sera levée et le programme 'plantera'. On écrit donc avant l'instruction CType un Try pour capter l'erreur:

Tester s'il y a une erreur, la capter.

 
Sélectionnez

Private Sub Button3_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button3.Click

Dim i As Integer

Try

    i = CType(TextBox1.Text, Integer)

Catch

    MsgBox("saisir un nombre")

End Try

End Sub

V-AA-3. Les erreurs de logique

Image non disponible

Le programme fonctionne, pas d'erreurs apparentes, mais les résultats sont erronés, faux.

Il faut faire des tests dans les conditions réelles avec des données courantes, mais aussi avec des données remarquables (limites supérieures, inférieures, cas particuliers..) pour voir si les résultats sont cohérents et exacts.

Une fois l'erreur trouvée, il faut en déterminer la cause et la corriger.

Ou bien elle est évidente à la lecture du code ou bien elle n'est pas évidente et c'est l'horreur.

Dans ce dernier cas il faut analyser le fonctionnement du programme pas à pas, instruction par instruction en surveillant la valeur des variables.(voir la rubrique débogage )

Les erreurs les plus communes sont:

Utilisation d'un mauvais nom de variable (La déclaration obligatoire des variables évite cela)
Erreur dans la portée d'une variable.
Erreur dans le passage de paramètres (Attention au By Val et By Ref)
Erreur dans la conception de l'algorithme.
...

Quelques règles permettent de les éviter: voir Règles de bonne programmation.

V-AA-4. Les Tests

Il faut donc toujours tester le fonctionnement du programme de multiples fois:

On fera des:
  • Tests unitaires: qui testeront les procédures, les classes une à une sans tester la totalité du programme.
  • Tests de composants et d'intégration: qui testeront plusieurs procédures ou classes fonctionnant ensemble.
  • Tests de régression: c'est la répétition des test précédents afin de voir si une modification ou un ajout n'entraîne pas de nouvelles erreurs qui n'existaient pas.
  • Tests système: test sur le logiciel dans sa version finale.

Les tests détecteront les erreurs, le débogage permettra de trouver la cause et de corriger l'erreur.

Il faut avoir une armée de Bêta-testeurs.


précédentsommairesuivant

Vous avez aimé ce tutoriel ? Alors partagez-le en cliquant sur les boutons suivants : Viadeo Twitter Facebook Share on Google+   

  

Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright © . Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.