IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Windows Forms Discussion :

[VB.NET] ByVal qui réagie comme un ByRef


Sujet :

Windows Forms

  1. #1
    Membre actif
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Septembre 2003
    Messages
    399
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur .NET

    Informations forums :
    Inscription : Septembre 2003
    Messages : 399
    Points : 259
    Points
    259
    Par défaut [VB.NET] ByVal qui réagie comme un ByRef
    Bonjour,

    Je mets plusieurs classe "Personne" dans ma combo.
    Dans une fonction je passe l'item sélectionné en Byval et dans la fonction je modifie les valeurs.
    La logique veut qu'en passant un paramètre en ByVal à la sortie de la fonction celui n'est pas modifié.
    Sauf que là ce n'est pas le cas.

    Si on rappel l'item sélectionné celui a changé de valeur.


    Le code ci-dessous n'a aucun intérêt sauf à servir de démo

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
     
    Public Class Form1
     
        Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
            Dim p As Personne
     
            p = New Personne
            p.nom = "AAAAA"
            p.prenom = "BBBBB"
            MyCombo.Items.Add(p)
            p = Nothing
     
            p = New Personne
            p.nom = "CCCCC"
            p.prenom = "DDDDDD"
            MyCombo.Items.Add(p)
            p = Nothing
        End Sub
     
        Private Function DEMO_DU_ByVal(ByVal pers As Personne) As String
            pers.nom = "Erreur1"
            pers.prenom = "Erreur2"
            Return "ok"
        End Function
     
        Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
            MessageBox.Show(DEMO_DU_ByVal(CType(MyCombo.SelectedItem, Personne)))
            MessageBox.Show(CType(MyCombo.SelectedItem, Personne).ToString)
        End Sub
     
        Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
            MessageBox.Show(CType(MyCombo.SelectedItem, Personne).ToString)
        End Sub
    End Class
     
    Public Class Personne
        Public nom As String = ""
        Public prenom As String = ""
     
        Public Overrides Function ToString() As String
            Return nom & " " & prenom
        End Function
    End Class
    Alors normal ou est-ce un bug ?

  2. #2
    Rédacteur

    Avatar de Jérôme Lambert
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Novembre 2003
    Messages
    4 451
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : Belgique

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Novembre 2003
    Messages : 4 451
    Points : 14 357
    Points
    14 357
    Par défaut
    Les classes sont toutes des types références. Donc passer une instance d'une classe par valeur, ça ne sert à rien.

    Ou alors je suis à côté de la plaque
    D'ailleurs, ça m'étonne que tu n'aies pas un warning voir une erreur
    Jérôme Lambert
    Développeur, Architecte, Rédacteur & Fan technologies Microsoft
    Ma boite informatique | Mon profil LinkedIn

  3. #3
    Membre actif
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Septembre 2003
    Messages
    399
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur .NET

    Informations forums :
    Inscription : Septembre 2003
    Messages : 399
    Points : 259
    Points
    259
    Par défaut
    Non je n'ai aucun message d'erreur ou ni de warning.

    Les classes sont toutes des types références
    Je ne savais pas.

    Donc ceci explique cela.

    merci pour l'infos

  4. #4
    Rédacteur

    Avatar de Jérôme Lambert
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Novembre 2003
    Messages
    4 451
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : Belgique

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Novembre 2003
    Messages : 4 451
    Points : 14 357
    Points
    14 357
    Par défaut
    J'ai peut être parlé trop vite... Apparement on peut passer des références de classe par valeur... Mais je ne suis pas sûr et j'ai pas le temps de vérifier.

    Voici quand même un lien où tu pourras en apprendre plus : http://msdn2.microsoft.com/en-us/library/sect4ck6.aspx
    Jérôme Lambert
    Développeur, Architecte, Rédacteur & Fan technologies Microsoft
    Ma boite informatique | Mon profil LinkedIn

  5. #5
    Membre régulier
    Profil pro
    Inscrit en
    Octobre 2003
    Messages
    66
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Octobre 2003
    Messages : 66
    Points : 80
    Points
    80
    Par défaut
    Il y a deux types de variables en .NET : les value type et les référence type.
    Le type d'une variable influe sur la façon dont elle est passée en paramètre.
    Value type = boolean, int, short, long,... et les struct
    Reference type = classes (string inclu)

    D'un autre coté il y a ByVal et Byref qui spécifie comment sont passées les variables.
    ByVal = variable passée par valeur
    ByRef = variable passée par référence

    Maintenant mixons les deux.
    Un value type passé par valeur : la valeur est copiée et est passée à la méthode appelée. Si on modifie la valeur dans la méthode appelée cela n'affecte PAS l'appelant.
    Exemple :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
            Public Sub Main()
                Dim val As Integer = 1
                Console.WriteLine(val)
            End Sub
     
            Private Sub Modifieur(ByVal variable As Integer)
                variable = 42
            End Sub
    Ce code affichera "1"


    Un value type passé par référence : dans ce cas la valeur n'est PAS copiée. A la place l'argument pointe vers la variable de l'appelant (val dans ce cas). Si on modifie la valeur dans la méthode appelée cela affecte l'appelant.
    Exemple :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
            Public Sub Main()
                Dim val As Integer = 1
                Console.WriteLine(val)
            End Sub
     
            Private Sub Modifieur(ByRef variable As Integer)
                variable = 42
            End Sub
    Ce code affichera "42"

    Jusqu'ici rien de compliqué.
    Maintenant occupons nous des reference type (les classes).
    Ici les choses se corsent. En effet, qu'est ce qu'une variable de type reference? Et bien en fait c'est un POINTEUR vers une donnée.
    Par exemple si l'on a :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Dim val as String = "hello"
    en fait la variable val contient un pointeur et ce pointeur contient une adresse représentant ou est situé "hello" dans la mémoire.
    Voila ce que ca donne avec un schema :


    Si ca me chante je pourrais créé une deuxième variable qui pointe vers la string :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Dim val2 as String = val


    Dans ce cas si je modifie une des deux variables (val ou val2) je modifierais également l'autre! Si je fait val.monChamp = "blah", val2 reflètera également ce changement car val et val2 pointent vers la même chose ok?

    Maintenant voyons ce qui se passe quand un "reference type" (= classes) est passé avec ByVal et ByRef
    Le secret avec les reference types c'est que peut importe que tu utilises ByVal ou ByRef l'objet n'est PAS copié. Il est juste "passé" à l'appelant. La méthode appelante et la méthode appelée voient le même objet (le même espace mémoire). Donc si dans la méthode appelée tu modifie l'objet passé, l'objet de l'appelant sera affecté aussi vu que c'est le même!
    Exemple :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
            Public Sub Main()
                Dim val As New MaClasse
                val.membre = "hello"
                Console.WriteLine(val)
            End Sub
     
            Private Sub Modifieur(ByVal variable As MaClasse)
                variable.membre = "world"
            End Sub
    Ce code affichera "world" car val et variable pointent vers le même objet.
    ByVal aurait pu être remplacé par ByRef et cela n'aurait rien changé au résultat!

    Maintenant tu va me dire, mais alors ya aucune différence entre utiliser byval et byref quand la variable passée est une classe (=reference type) ?
    Et bien en fait si!
    Avec ByVal le pointeur passé à la méthode appelée est COPIÉ !. Il y a donc deux pointeur vers l'objet :


    Dans le cas du ByRef le pointeur n'est PAS copié, il est juste passé à l'appelant :

    Comme tu peux le voir, avec ByRef les deux variable "pointent" vers le même pointeur!

    Tu va me dire, c'est bien l'ami mais quel est la différence?
    Et bien il y a une différence si tu fait une assignation, c'est à dire faire pointer une variable vers autre chose.
    Exemple :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
            Public Sub Main()
                Dim val As String = "hello"
                Console.WriteLine(val)
            End Sub
     
            Private Sub Modifieur(ByVal param As String)
                param = "world"
            End Sub
    Note que dans ce cas ByVal est utilisé.
    Avec ByVal, quand on fait param = "world", c'est la COPIE du pointeur qui est modifié. param pointe vers "world" mais val pointe toujours vers le "hello" car ce sont deux pointeurs différents.
    Voici ce qui se passe dans la mémoire :

    Le code affiche donc "hello" !

    Par contre avec ByRef :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
            Public Sub Main()
                Dim val As String = "hello"
                Console.WriteLine(val)
            End Sub
     
            Private Sub Modifieur(ByRef param As String)
                param = "world"
            End Sub
    Ici quand on fait param = "world", val est modifié avec param car la variable val et la variable param pointent vers la même chose!
    Voici ce qui se passe dans la mémoire :

    Le code affiche donc "world" !

    C'est le genre de truc qui est facile a comprendre quand on représente ce qui se passe sur un tableau ou un bout de feuille mais qu'il est difficile d'expliquer oralement ou par écrit.

    Si tu veux plus d'info tu peux aller voir Java is Pass-By-Value, Dammit!
    Ca parle de Java mais ca fonctionne de la même façon, a part qu'en java il n'y a que le ByVal, il n'y a donc pas d'équivalent du byref.

  6. #6
    Membre confirmé Avatar de joKED
    Profil pro
    Imposteur en chef
    Inscrit en
    Février 2006
    Messages
    337
    Détails du profil
    Informations personnelles :
    Âge : 42
    Localisation : France, Isère (Rhône Alpes)

    Informations professionnelles :
    Activité : Imposteur en chef

    Informations forums :
    Inscription : Février 2006
    Messages : 337
    Points : 458
    Points
    458
    Par défaut
    Oui, je déterre un topic, c'est vrai.

    Mais cette réponse de Monkeyget, je trouve qu'elle mérite largement sa place dans la FAQ, car je la trouve extrèmement pédagogique, et je suis sur qu'elle sauvera la vie d'un grand nombre d'utilisateurs (surtout ceux qui, comme moi, n'ont jamais eu le moindre cours sur des langages utilisant des pointeurs, et qui, de ce fait, utilisent souvent byval et byref sans imaginer à quel point le passage d'un reference type dans un byval peut entrainer des conséquences fâcheuses)

    En tout cas, merci Monkeyget!
    Tant va la cruche à l'eau qu'à la fin y'a plus d'eau.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. [Studio .NET] Executable qui marche sur des PC différents
    Par black is beautiful dans le forum Autres Logiciels
    Réponses: 3
    Dernier message: 05/10/2005, 17h00
  2. [VB.NET] Update qui ne se réalise pas
    Par totoche dans le forum ASP.NET
    Réponses: 4
    Dernier message: 20/05/2005, 11h16
  3. [VB.NET] DataReader qui prend enormement de memoire
    Par JohnGT dans le forum Windows Forms
    Réponses: 9
    Dernier message: 07/01/2005, 17h38
  4. [VB.NET] DataSet qui ne retourne pas de résultat
    Par Lois dans le forum Windows Forms
    Réponses: 4
    Dernier message: 02/06/2004, 17h07
  5. [VB.NET] Classe qui pilote des Fichier .INI
    Par sygale dans le forum Windows Forms
    Réponses: 3
    Dernier message: 01/06/2004, 20h04

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo