Une visionneuse d'image en VB.NET

1. October 2010 by Jordan.BERTHELEMY

 

Introduction :

Cet article va vous apprendre comment créer une visionneuse d’image en VB.NET. Pour ceux qui ne sauraient pas ce qu’est une visionneuse d’image, voici celle de Windows. A la fin de ce TP nous devrions avoir un résultat similaire.

Objectifs de cet article :

-          Créer des contrôles et des évènements

-          Créer un menu

-          Lister les fichiers présents dans un dossier

-          Imprimer une image

-          Copier une image dans le presse-papier

-          Supprimer un fichier

-          Faire pivoter une image

 

Première étape : Création du projet

La première étape consiste à créer un nouveau projet Visual Basic - Windows Form Application. Donnez-lui le nom de votre choix, moi j’ai choisi ImageViewer. Ce projet a été réalisé à l’aide de Visual Studio 2010 Ultimate.

Vous devriez voir un onglet appelé Form1.vb [Design]. A l’intérieur se trouve une fenêtre nommée Form1. Dans ses propriétés changez les attributs Name et Text pour ImageViewer et mettez l’attribut Size à 800 ; 600.


Deuxième étape : Création des contrôles

Pour créer un menu, utilisez le MenuStrip de la boîte à outils et insérez le dans la fenêtre. Créez le sous-menu Fichier qui contient les options : Ouvrir,  Copier, Imprimer, Supprimer et Quitter.

Ensuite il faut ajouter des boutons. Il en faut six : Suivant, Précédent, Diaporama, Rotation Gauche, Rotation Droite et Supprimer. Tous les boutons sont placés dans un Panel. Mettez la propriété Visible du Panel à False pour éviter que les boutons soient visibles lorsqu’aucune image n’est affichée dans la PictureBox Il faut également ajouter une PictureBox au milieu de la fenêtre. La propriété SizeMode de la PictureBox doit être à StretchImage.

Pour mettre des images dans les boutons, rendez-vous dans les Propriétés du projet (Projet, Propriétés de ImageViewer) puis dans Ressources. Ajoutez-y les images que vous souhaitez utiliser. Celles qui apparaissent sur les captures d’écran proviennent d’IconFinder. Ensuite il suffit de modifier la propriété Image des boutons.

Pour afficher des informations sur les boutons il faut créer un ToolTip et modifier la propriété « Tooltip sur NomDeVotreTooltip » de chacun des boutons.


Troisième étape : Création d’une classe Viewer

Une fois tous les contrôles créés, ajoutez une Classe au projet. Pour cela, clic droit sur le projet, Ajouter, Classe. Appelez cette classe Viewer et ajoutez-y deux régions, une pour les attributs de la classe et l’autre pour les méthodes. Les régions ne sont en aucun cas nécessaires mais elles permettent de mieux organiser le code.

Vous devriez avoir quelque chose de ce type :

Public Class Viewer

#Region “Attributs”
#End Region

#Region “Méthodes”
#End Region

End Class

Cette classe contient deux attributs : tabImages qui est une liste contenant des liens absolus vers les images présentes dans le même dossier que l’image ouverte et current qui contient le numéro de l’image affichée.

#Region “Attributs”

Private tabImages As New ArrayList 'Liste contenant un lien absolu vers toutes les images présentes dans le dossier

                Private current As Integer 'Numéro de l'image affichée
#End Region

 

La fonction GetFiles :

Une fonction Getfiles existe déjà mais ne permet pas de lister les fichiers d’un répertoire en fonction de plusieurs extensions.

Public Function GetFiles(ByVal repertoire As String, ByVal extensions As String()) As String()

        Dim fichiers As List(Of String) = New List(Of String)()

        For Each extension As String In extensions

fichiers.AddRange(IO.Directory.GetFiles(repertoire, extension, IO.SearchOption.TopDirectoryOnly))

        Next

        Return fichiers.ToArray()

    End Function

 

 

Cette fonction accepte plusieurs paramètres : une chaine de caractères indiquant le chemin vers le répertoire dont veut lister les fichiers ainsi qu’un tableau de chaines de caractères. Ce tableau contient la liste des extensions qu’il faut prendre en compte. Elle renvoi un tableau de chaines de caractères qui sont les noms des fichiers dont les extensions correspondent à celles présentes dans le tableau. Pour chaque extension du tableau cette fonction va appeler la méthode GetFiles de la classe Directory.

IO.SearchOption.TopDirectoryOnly signifie que seuls les fichiers présents dans le répertoire actif sont listés et pas ceux des sous-répertoires.

Vous pouvez commenter les fonctions, pour cela ajoutez ''' (3 apostrophes) au dessus de la fonction. Vous devriez voir apparaitre les lignes ci-dessous.

    ''' <summary>

    '''

    ''' </summary>

    ''' <param name="parametre1"></param>

    ''' <param name="parametre2"></param>

    ''' <returns></returns>

    ''' <remarks></remarks>

Il suffit ensuite d’ajouter du texte entre les balises.

 

Le constructeur :

Le constructeur est une méthode qui est appelée au moment où un objet est créé, cette méthode a pour but d’initialiser les attributs de l’objet. Ici, le constructeur ne prendra aucun paramètre.

Sub New()

                For Each image As String In GetFiles(IO.Directory.GetParent(ImageViewer.OpenImage.FileName).FullName,{"*.jpg", "*.jpeg", "*.png", "*.gif", "*.bmp"})

                               tabImages.Add(image)

                Next

                               current = tabImages.IndexOf(ImageViewer.OpenImage.FileName)

                               Afficher_image(current)

End Sub

Le constructeur appelle la fonction GetFiles que vous avez créée plus tôt pour lister tous les fichiers ayant pour extension jpg, jpeg, png, gif ou bmp présents dans le même répertoire que l’image que l’utilisateur décide d’ouvrir. Chaque image du tableau renvoyé par la fonction GetFiles est ajoutée dans tabImages. Current prend pour valeur l’index de l’image ouverte par l’utilisateur.

 

La méthode Afficher_image :

    Public Sub Afficher_image(ByVal num_image As Integer)

        Try

            ImageViewer.PB_Image.Image = Image.FromFile(tabImages(num_image))

            Redim_image()

        Catch

            tabImages.RemoveAt(num_image)

            current += 1

            Afficher_image(current)

        End Try

    End Sub

 

Cette méthode prend un nombre en paramètre et permet d’afficher l’image ayant ce nombre pour index dans tabImages pour ensuite la redimensionner. Si l’application n’arrive pas à ouvrir une image (ce qui peut arriver si l’utilisateur l’a supprimée entre temps) alors elle est retirée de la liste et l’image suivante est affichée et la valeur de current est incrémentée.

ImageViewer est la classe qui contient tous les contrôles et les évènements qui y sont liés. PB_Image est le nom donné à la PictureBox, Image est la propriété qui a pour valeur l’image à afficher.

La méthode Redim_image :

    Public Sub Redim_image()

If ImageViewer.PB_Image.Image.Height <= ImageViewer.PB_Image.MaximumSize.Height And ImageViewer.PB_Image.Image.Width <= ImageViewer.PB_Image.MaximumSize.Width Then 'Si l'image a des dimensions plus petites que la taille maximum de la PictureBox

            ImageViewer.PB_Image.Size = ImageViewer.PB_Image.Image.Size

        Else

ImageViewer.PB_Image.Width = (ImageViewer.PB_Image.Image.Width * ImageViewer.PB_Image.MaximumSize.Height) / ImageViewer.PB_Image.Image.Height

 

ImageViewer.PB_Image.Height = (ImageViewer.PB_Image.Image.Height * ImageViewer.PB_Image.MaximumSize.Width) / ImageViewer.PB_Image.Image.Width

        End If 

ImageViewer.PB_Image.SetBounds(((ImageViewer.Width - ImageViewer.PB_Image.Width) / 2), ((ImageViewer.Height - ImageViewer.PB_Image.Height) / 2), ImageViewer.PB_Image.Width, ImageViewer.PB_Image.Height)

    End Sub

Si la hauteur et la largeur de l’image affichée sont inférieures à la hauteur et la largeur maximum de la PictureBox alors les dimensions de la PictureBox prennent celles de l’image pour valeur. Sinon elle est redimensionnée proportionnellement aux dimensions de l’image et aux dimensions maximums de la PictureBox. Une fois redimensionnée, elle est placée au centre de la fenêtre.

 

La méthode Image_suivante :

                Public Sub Image_suivante()

                               If current = (tabImages.Count - 1) Then

                                               Afficher_image(0)

                                               current = 0

                               Else

                                               Afficher_image(current + 1)

                                               current += 1

                               End If

                End Sub


Cette méthode affiche l’image qui se situe après l’image actuelle. Si l’index de l’image actuelle est égal au nombre d’éléments présents dans la liste – 1 (car une liste commence à 0) alors current prend 0 pour valeur sinon sa valeur est augmentée de 1.

 

La méthode Image_precedente :

Public Sub Image_precedente()

                If current = 0 Then

                               Afficher_image(tabImages.Count - 1)

                               current = tabImages.Count - 1

                Else

                               Afficher_image(current - 1)

                               current -= 1

                End If

End Sub


Cette méthode fonctionne sur le même principe que Image_suivante. Si l’index de l’image courante est 0  alors current vaut la taille de la liste - 1, dans le cas contraire il y a décrémentation de la valeur de current.

La méthode Rotation_image :

Public Sub Rotation_image(ByVal sensHoraire As Boolean)

If sensHoraire = False Then

ImageViewer.PB_Image.Image.RotateFlip(RotateFlipType.Rotate270FlipNone) 'Rotation de 90° dans le sens anti-horaire

ElseIf sensHoraire = True Then

ImageViewer.PB_Image.Image.RotateFlip(RotateFlipType.Rotate90FlipNone) ' Rotation de 90° dans le sens horaire

                End If

                Redim_image()

End Sub


Cette méthode prend un Booléen en paramètre. Ce booléen vaut True si la rotation se fait sans le sens horaire et False dans le sens anti-horaire. Après la rotation, l’image est redimensionnée pour qu’elle s’affiche correctement. Si elle n’était pas redimensionnée les proportions ne seraient pas conservées et l’affichage serait donc incorrect.

 

La méthode Supprimer_image :

Public Sub Supprimer_image()

ImageViewer.PB_Image.Image.Dispose()

Try ' Si une image est supprimée on l'enlève de la liste et on affiche la suivante

My.Computer.FileSystem.DeleteFile(tabImages(current), FileIO.UIOption.AllDialogs, FileIO.RecycleOption.SendToRecycleBin)

tabImages.RemoveAt(current)

current += 1

Afficher_image(current)

Catch 'Si l'utilisateur clique sur Annuler cela lève une exception

End Try

End Sub


Cette méthode envoi l’image courante à la corbeille. La boite de dialogue demandant confirmation est affichée. Si l’utilisateur clique sur Non ou ferme la boite de dialogue, une exception est levée, dans ce cas aucune instruction n’est exécutée. Si l’utilisateur clique sur Oui l’image est retirée de la liste et l’image suivante est affichée.

Qutrième étape : Création des évènements

Dans la classe ImageViewer, donc celle qui correspond à notre fenêtre, déclarez un objet de type viewer.

Dim viewer As Viewer


Evènements liés aux éléments du menu :


Ouverture d’une image :

Private Sub Ouvrir_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Ouvrir.Click

OpenImage.Filter = "Images| *.jpg; *.jpeg; *.gif; *.png; *.bmp"

If OpenImage.ShowDialog() = DialogResult.OK Then

viewer = New Viewer()

P_Boutons.Visible = True

End If

End Sub


Un filtre est créé pour qu’on ne puisse ouvrir que des images. Si une image est choisie alors le constructeur de la classe Viewer est appelé et les boutons sont affichés.

Copier une image dans le presse-papier :

Private Sub Copier_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Copier.Click

        If PB_Image.Image IsNot Nothing Then

            Clipboard.SetDataObject(PB_Image.Image)

        End If

End Sub


Si une image est affichée alors elle est placée dans le presse-papier. Elle pourra ensuite être collée dans un autre document.

 

Imprimer une image :

Private Sub Imprimer_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Imprimer.Click

        If PB_Image.Image IsNot Nothing Then

            PrintOptions.Document = Me.PrintImage

            If PrintOptions.ShowDialog() = DialogResult.OK Then

                Try

                    PrintImage.Print()

                Catch

                End Try

            End If

        End If

End Sub

 

Private Sub PrintImage_PrintPage(ByVal sender As System.Object, ByVal e As System.Drawing.Printing.PrintPageEventArgs) Handles PrintImage.PrintPage

        e.Graphics.DrawImage(PB_Image.Image, PB_Image.Bounds)

End Sub

 


Ces évènements sont appelés lorsque l’utilisateur veut imprimer une image. Créez deux autres contrôles dans le projet : un PrintDocument, appelé PrintImage et un PrintDialog, appelé PrintOptions. Si une image est affichée, alors le document à imprimer est cette image. Si l’impression est annulée ou ne fonctionne pas, une exception est levée.

Supprimer une image :

Private Sub Supprimer_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Supprimer.Click

        If PB_Image.Image IsNot Nothing Then

            viewer.Supprimer_image()

        End If

End Sub


Si une image est affichée alors on appelle la méthode Supprimer_image.

Quitter :

Private Sub Quitter_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Quitter.Click

        End

End Sub


Cet évènement arrête l’exécution de l’application et ferme la fenêtre.

Evènements liés aux boutons :

Le bouton Précédent :

Private Sub BT_Precedent_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles BT_Precedent.Click

        viewer.Image_precedente()

End Sub


Lorsqu’il y a un clic sur ce bouton, la méthode Image_precedente est appelée.

 

Le bouton Diaporama :

Private Sub BT_Diaporama_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles BT_Diaporama.Click

        Me.FormBorderStyle = Windows.Forms.FormBorderStyle.None

        Me.TopMost = True

        Me.WindowState = FormWindowState.Maximized

        P_Boutons.Hide()

        M_Menu.Hide()

        Cursor.Hide()

        Me.Focus()

        timer.Enabled = True

End Sub

 

Private Sub timer_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles timer.Tick

        viewer.Image_suivante()

End Sub

 

Shadows Sub KeyDown(ByVal sender As System.Object, ByVal e As System.Windows.Forms.KeyEventArgs) Handles MyBase.KeyDown

        If Me.WindowState = FormWindowState.Maximized Then

            If e.KeyCode = Keys.Escape Then

                Me.FormBorderStyle = Windows.Forms.FormBorderStyle.Sizable

                Me.WindowState = FormWindowState.Normal

                Me.TopMost = False

                P_Boutons.Show()

                M_Menu.Show()

                Cursor.Show()

                timer.Enabled = False

            End If

        End If

End Sub


Pour gérer le diaporama, créez un nouveau contrôle de type Timer. Mettez ses propriété Enabled à false et Interval à 5000ms. Une fois le timer déclenché il va appeler la méthode Image_suivante toutes les cinq secondes.

Lorsqu’il y a un clic sur le bouton Diaporama, les bordures de la fenêtre sont masquées, la fenêtre est affichée au premier plan et en plein écran. Les boutons, le curseur et le menu sont cachés et le timer est déclenché.

Pour arrêter le diaporama, ajoutez un évènement de type KeyDown sur la fenêtre. Si la fenêtre est en plein écran et qu’’il y a un appuie sur la touche Echap alors la fenêtre est remise dans son état précédent ; c’est-à-dire mode fenêtré avec bordures,  réaffichage des boutons, du curseur et du menu puis on arrêt du timer.

Le bouton Suivant :

Private Sub BT_Suivant_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles BT_Suivant.Click

        viewer.Image_suivante()

End Sub


Lorsqu’on clique sur ce bouton, la méthode Image_suivante est appelée.

 

Le bouton Rotation Gauche :

Private Sub BT_Gauche_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles BT_Gauche.Click

        viewer.Rotation_image(False)

End Sub


Un clic sur ce bouton appelle la méthode Rotation_image avec False en paramètre, ce qui veut dire que la rotation se fera dans le sens anti-horaire.

Le bouton Rotation Droite :

Private Sub BT_Droite_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles BT_Droite.Click

        viewer.Rotation_image(True)

End Sub


Un clic sur ce bouton appelle la méthode Rotation_image avec True en paramètre, ce qui veut dire que la rotation se fera dans le sens horaire.

Le bouton Supprimer :

Private Sub BT_Supprimer_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles BT_Supprimer.Click

        viewer.Supprimer_image()

End Sub


Ce bouton appelle la méthode Supprimer_Image.

Redimensionnement de la fenêtre :

Private Sub ImageViewer_SizeChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.SizeChanged

        PB_Image.MaximumSize = New Size((Me.Width), (Me.Height - 80))

        If PB_Image.Image IsNot Nothing Then

            viewer.Redim_image()

        End If

End Sub


Ajoutez un évènement SizeChanged sur la fenêtre. Lorsque la taille de la fenêtre change, les dimensions maximum de la PictureBox changent et si une image est affichée elle est redimensionnée.

Me.Height – 80 Permet de ne pas afficher une image au dessus des boutons ou du menu.

vb.net, Visual Studio 2010

VB10 et C# 4 : les langages .net évoluent

1. April 2010 by Benjamin.Robic

1 - Introduction


 

Visual Studio 10 pointant le bout de son nez ce début d’année, un point sur les nouveautés qu’amène cette version serait de bon augure !

Avec cette nouvelle mouture apparait la venue du tout nouveau, tout beau framework 4.0 et avec celui-ci, la nouvelle version des 2 langages : C# 4.0 et VB 10.

Dans cet article, nous tâcherons de voir les nouveautés apportées aux 2 langages parmi lesquelles les instructions dynamiques et la covariance/contravariance.

 

2 - Les évolutions du langage C# 4.0


 

Les évolutions pour le langage C# sont minimes. En effet, elles ont pour but uniquement de faciliter l’usage des paramètres dans les fonctions.

Pour cela, C# autorise dorénavant les paramètres nommés et les paramètres optionnels. Ils peuvent donc maintenant être utilisés directement lors de la définition de méthodes, constructeurs et indexeurs. Voici un petit exemple :

 

             a) Les paramètres optionnels

 

On parle de paramètres optionnels lorsque l’on attribue à des paramètres, une valeur par défaut.

Ces valeurs sont utilisées si lors de l’appel à la fonction, il n’y a pas de valeur spécifiée pour ces paramètres. Cependant, il faut obligatoirement respecter l'ordre des paramètres. 

 

Ex : Dans l’exemple, on a : b = 10 et c = 6

 

 

       

        b) Les paramètres nommés

 

On parle de paramètres nommés, quand on précise leurs noms et leurs valeurs séparés de « : ».

Cela permet d’alléger le code, et de ne pas se préoccuper de l’ordre des paramètres lorsqu’ils sont nommés !

Ex : Dans l’exemple, on a : b = 10 et c = 6

 

 

 

    3 - Les évolutions du langage VB 10.0


 

Nous allons voir que contrairement au langage C# 4.0, le langage VB 10.0 a été lui littéralement révolutionné empruntant au passage les fonctionnalités déjà existantes du C#.    

 

        a) Le saut d'instruction d'implicite


Sous ces termes barbares se cache la possibilité de déclarer une chaîne de caractères en une seule instruction sur plusieurs lignes sans passer par le caractère de saut d’instruction « _ ». Il devient donc plus pratique d’écrire un long string.

 

Avant :

 

 

 

Maintenant:

 

 

 

             b) Les instructions lambda multi-lignes


Pour vous expliquer en quoi cela consiste, un petit exemple. Ce bout de code permet de réaliser un traitement sur des chaînes de caractères de manière asynchrone (voir ci-dessous).

 

 

On remarque que pour pouvoir exécuter le code de manière asynchrone, on est obligé de créer une nouvelle méthode dans la classe.

Dorénavant, grâce à Visual Basic 10.0, on peut écrire directement le bout de code grâce aux instructions lambda multi-lignes. On a donc plus besoin de créer une nouvelle méthode dans la classe (voir ci-dessous).

 

 

         c) Les initialiseurs de collection


Encore une évolution tenant à remettre à niveau VB par rapport à C#. En effet, depuis VB 9.0, on peut initialiser des objets à partir d’une classe en spécifiant directement dans l’instruction, l’instanciation de l’objet et son initialisation.

Maintenant avec VB 10.0, on peut initialiser des collections.

Comme un exemple est plus parlant que du texte, je vous montre :

 

L’exemple ci-dessus montre comment créer une collection de notes grâce à l’utilisation du mot-clé « From ».

 

 

L’exemple ci-dessus montre comment créer une collection d’objets de type « Personne ». On voit aussi que l’on peut directement initialiser l’objet grâce au mot-clé « With ».

 

              d) Les propriétés simplifiées

 

Pour faire simple, ces propriétés permettent de définir dans une classe, des propriétés sans avoir besoin d’implémenter les attributs qu’ils gèrent, ni le corps des accesseurs (getter/setter). Cela correspond aux accesseurs simplifiés ( { get; set; } ) présents depuis C# 3.0 dans Visual Studio 2008. On parle en anglais de « Auto Properties », ou bien encore d’ « Auto-Implemented Properties ». L’intérêt de cette « nouveauté » est d’écrire moins de code dans les classes et de rajouter au VB, une fonctionnalité déjà présente en C#.

 

 

Dans l’exemple ci-dessus, on voit les 2 déclarations possibles :

-          L’ « ancienne » : déclaration d’un attribut  « Prénom » avec sa propriété prénom d’une Personne

-          la « nouvelle » : déclaration d’une propriété « Nom » contenant le nom d’une Personne. On remarque que celle-ci n’a pas d’accesseurs : c’est une propriété simplifiée !

Les 2 déclarations sont bonnes et donnent le même résultat. On peut d’ailleurs le vérifier en utilisant « Reflector »:

 

 

    4 - Les évolutions communes aux 2 langages



C’est lors de la « Professional Developers Conference 2008 » que Microsoft annonçait qu’à partir de la version Visual Basic 10 et la version C# 4, ils évolueraient ensemble. Ces versions étant maintenant arrivées, voyons les nouvelles possibilités qu’elles nous proposent ! 

 

        a) Les instructions lambda multi-lignes

 

Le but du typage dynamique est de pouvoir créer des instructions dynamiques. Grâce à ces dernières, il est possible de déclarer des variables locales, des attributs de classes ou autres paramètres de méthodes, qui seront typés lors de l’exécution de l’application et non pas comme normalement, lors de la compilation: c’est ce que l’on appelle, des « liaisons tardives » : le typage dynamique se fait par l’intermédiaire du mot-clé « dynamic ». Cela va nous permettre par exemple, d’appeler n’importe quel méthode, d’accéder à un index, à des champs ou des propriétés, sans qu’il n’y ait aucune vérification lors de la compilation. Vous l’aurez donc compris, il faut quand même faire attention avec cette nouveauté…

Mais il y a aussi de nombreux avantages. En outre, on note que l’on pourra beaucoup plus facilement manipuler des objets issus de langage de programmation dits « dynamiques » ( Ruby, Python), simplifier l’utilisation d’objets là où on utilisait la réflexion et de pouvoir manipuler des objets « à structures changeantes » comme les objets HTML et DOM.

 

         b) Exemples pour mieux comprendre

                   1.      Premier exemple

 

L’exemple ci-dessous illustre bien ce qui est dit plus haut :

 

 

En effet, Visual Studio 2010 ne voit pas d’erreur dans ce bout de code alors que sous VS 2008, nous aurions une erreur de typage. Le fait est qu’ici, les 2 variables « monString » et « monInt » sont appelées dynamiquement. La fonction ShowVariableDynamic récupère ces variables et les types automatiquement lors du runtime.

Le résultat donne logiquement :

 

 

 

                   2.      Deuxième exemple un peu plus complexe

 

Ce deuxième exemple va vous montrer que l’on peut aussi appeler des méthodes sans avoir au préalable, typée la variable.

Soit la classe Policier avec comme attributs, un nom et un prénom. On crée une méthode dans cette classe qui affichera une petite phrase de présentation.

 

 

On crée ensuite une méthode « SePresenter » qui aura un paramètre défini de manière dynamique et auquel on appliquera la méthode précédemment définie, Presentation.

 

 

Le bloc d’instructions crée une instance de la classe Policier et exécute la méthode  SePresenter sur l’objet crée.

 

 

On a alors ce résultat :

 

 

La méthode Presentation a bien été exécutée de manière dynamique car le type de l’objet (en paramètre) n’était pas explicitement défini lors de la compilation.

Attention toutefois à ne pas abuser de ce nouveau type. En effet, ces dynamiques restent quand même ‘dangereuses’ pour peu que l’on en abuse. On peut alors se retrouver face à un énorme bourbier car le compilateur n’effectue aucune vérification. Le mieux étant de typer convenablement dés que possible pour ne pas être confronté à d’éventuels pertes de performances et de soucis avec l’auto complétion…

 

        c) La "covariance" et la "contre-variance"

                   1.      Mise en situation

 

Il faut savoir que ces fonctionnalités existent depuis le framework 2.0 ! En effet, depuis VB 8.0 et c# 2, il est possible de les appliquer sur des délégués. Ce qui est nouveau, c’est que l’on peut dorénavant étendre les principes de « covariance » et de « contre-variance » aux interfaces génériques.

 

Un petit rappel sur la variance. Prenons un exemple pour illustrer celle-ci :

3-4 - Co- and Contra-Variance

Dans cet exemple, on déclare une liste générique de strings. Lors de l’exécution, le compilateur se chargera de vérifier que les accès à la liste ne sont uniquement que pour des types « string ». Essayons d’ajouter un string à la liste, puis un int :

 

 

On peut voir que si l’on ajoute un string, il n’y a pas de problème mais que si l’on veut ajouter un int, c’est impossible. Jusqu’ici tout va bien …

Le problème survient lorsque l'on essaye d’utiliser ce qu’on appelle « la variance de générique ». En effet, prenons le code suivant :

 

 

Visual Studio 2008 nous renvoie alors une belle erreur. Pourtant, il paraitrait logique qu’il n’y ait pas d’erreur puisque qu’un « integer » dérive du type « object ». C’est là que C# 4.0 et VB 10 interviennent ! Le framework 4.0 amène la solution à ces problèmes en amenant les mots-clés « in » et « out ».

 

                   2.      La covariance

 

Le framework amène donc avec lui, le mot-clé « out » permettant la covariance avec les génériques.

Le mieux pour comprendre est de prendre un exemple ! Penchons-nous sur la déclaration de l’interface IEnumerable :

 

 

Le mot clé « out » avant le type générique, est utilisé pour dire que le type T sera uniquement utilisable dans une position de sortie au sein de l’interface (comme type de retour des méthodes définies dans cette interface). On dit que l’interface est « covariante » de T.

En résumé, cela signifie que tout IEnumerable(A) sera considéré comme un IEnumerable(B) si et seulement si, A est une conversion de référence vers B.

Attention car la variance ne s’applique uniquement que lorsqu’il existe une conversion de référence entre 2 types d’arguments. Le cas échéant, elle ne pourra être utilisée. Un cas simple : un IEnumerable(integer) ne pourra pas être un IEnumerable(object) car la conversion d’un integer vers un object n’est pas une conversion de référence, c’est une conversion dite « de boxing »…

 

                   3.      La contravariance

 

Cette fois-ci, c’est la contravariance qu’amène le mot-clé « in » ! Comme toujours, prenons un exemple,  l’interface IEqualityComparer :

 

 

Cette fois-ci, le mot-clé « in » signifie que T peut se produire uniquement en position d’entrée au sein de l’interface.

On peut résumer ce cas logiquement. En effet, si un IEqualityComparer(T) est capable de comparer 2 objets quelconques du type « objects », alors forcément, il peut comparer 2 strings. C’est cette notion qu’on appelle « contravariance » !

 

    5 - Conclusion



Les nouveautés apportées par le framework 4.0 ne sont pas réellement de vraies révolutions des langages. Il s’agit plutôt de l’apport de différentes possibilités, et différentes évolutions visant à rendre les langages plus souples. Les amateurs de VB seront contents de voir que leur langage préféré a rattrapé son retard et est maintenant (presque) au niveau du C#.

En bref, ces 2 langages n’ont pas été révolutionnés. A part l’arrivée du typage dynamique (sujet à de multiples débats à mon humble avis) et les notions de variance et contravariance, rien de bien nouveau.

On reprend les mêmes et on recommence avec une version plus aboutie et un langage VB remis au niveau du C# pour faciliter la future coévolution.

C#, vb.net, Visual Studio 2010 , , ,