Bonjour,

Un des inconvénients de VB.NET est qu'on a parfois du mal à déterminer si on manipule une copie de la valeur d'un élément ou une référence vers cet élément.

Très concrètement : j'ai une petite classe qui permet de travailler avec des bitmaps, en accédant aux données brutes dans un tableau :

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
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
Public Class FastBitmap
    Public Bits As Int32()
    Public Height As Integer
    Public Width As Integer
 
    Private LockBmp As Bitmap
    Private BitsHandle As System.Runtime.InteropServices.GCHandle
 
    'Création à partir d'une image existante
    Public Sub New(file As String, Inverser As Boolean)
        Dim i As Integer, j As Integer
        Dim index As Integer, indexY As Integer
        Dim Bytes(4) As Byte
        Dim tmpBmp As Bitmap
        tmpBmp = CType(Image.FromFile(file), Bitmap)
        Width = tmpBmp.Width
        Height = tmpBmp.Height
        Bits = New Int32(Width * Height - 1) {}
        BitsHandle = System.Runtime.InteropServices.GCHandle.Alloc(Bits, System.Runtime.InteropServices.GCHandleType.Pinned)
        LockBmp = New Bitmap(Width, Height, Width * 4, System.Drawing.Imaging.PixelFormat.Format32bppPArgb, BitsHandle.AddrOfPinnedObject())
        Graphics.FromImage(LockBmp).DrawImage(tmpBmp, 0, 0) 'C'est un peu bourrin, mais fonctionne de façon sûr quel que soit le format d'image du fichier file
        tmpBmp.Dispose()
        'Maintenant, Bits(x + y * Width) contient la couleur ARGB sur 32 bits du pixel (x,y)
        'Chaque élement de Bits() est un Int32 dont on peut lire les 4 octets séparéments : Bytes(0)=B Bytes(1)=G Bytes(2)=R Bytes(3)=A 
        'Conversion niveau de gris :
        If Inverser Then
            For i = 0 To Height - 1
                indexY = i * Width
                For j = 0 To Width - 1
                    index = indexY + j
                    Bytes = BitConverter.GetBytes(Bits(index))
                    Bits(index) = FastBitmap_MAX_VALUE - 114000 * Bytes(0) - 587000 * Bytes(1) - 299000 * Bytes(2)
                Next
            Next
        Else
            For i = 0 To Height - 1
                indexY = i * Width
                For j = 0 To Width - 1
                    index = indexY + j
                    Bytes = BitConverter.GetBytes(Bits(index))
                    Bits(index) = 114000 * Bytes(0) + 587000 * Bytes(1) + 299000 * Bytes(2)
                Next
            Next
        End If
        'Maintenant, Bits(x + y * Width) contient la valeur de "Z" (niveau de gris) du pixel (x,y) sous forme de nombre entier compris entre 0 et FastBitmap_MAX_VALUE = 255000000
    End Sub
 
    'Création d'une image "vierge"
    Public Sub New(W As Integer, H As Integer)
        Width = W
        Height = H
        Bits = New Int32(Width * Height - 1) {}
        BitsHandle = System.Runtime.InteropServices.GCHandle.Alloc(Bits, System.Runtime.InteropServices.GCHandleType.Pinned)
        LockBmp = New Bitmap(Width, Height, Width * 4, System.Drawing.Imaging.PixelFormat.Format32bppPArgb, BitsHandle.AddrOfPinnedObject())
    End Sub
 
    'Retourne un objet graphics permettant de dessiner dans l'image
    Public Function GetGraphics(Optional sMode As Drawing2D.SmoothingMode = Drawing2D.SmoothingMode.None) As Graphics
        Dim g As Graphics
        g = Graphics.FromImage(LockBmp)
        g.SmoothingMode = sMode
        'Le SmoothingMode "none" est intéressant, il permet de dessiner avec une "fausse couleur" ARGB calculée pour correspondre à une valeur de Z précise de 0 à FastBitmap_MAX_VALUE
        Return g
    End Function
 
    Public Function GetFalseColor(Z As Int32, Optional Inverser As Boolean = False) As Color
        If Inverser Then Z = FastBitmap_MAX_VALUE - Z
        Return Color.FromArgb(Z)
    End Function
 
    Public Function GetFalseColor(ZPourcent As Double, Optional Inverser As Boolean = False) As Color
        Return GetFalseColor(CInt(ZPourcent * FastBitmap_MAX_VALUE), Inverser)
    End Function
 
    Public Sub Dispose()
        LockBmp.Dispose()
        BitsHandle.Free()
    End Sub
End Class
J'utilise ensuite cette classe dans mon code, et quand je fait cela :

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
 
Public Sub AddForme3D_GetExtrusionZFZ_Lithophanie(NbPointsXY As Integer, NbPointsZ As Integer,
                                                      file As String, CentreX As Double, CentreY As Double, ZBase As Double, ZoomXY_Value As List(Of Double), ZoomXY_Z As List(Of Double),
                                                      Amplitude As Double, ByRef Base As sPoly2D, ByRef Sommet As sPoly2D,
                                                      FaceEXT As Boolean, Inverser As Boolean, Couleur As Color)
'...
        Dim Bits As Int32()
        Dim Height As Integer
        Dim Width As Integer
        Dim fBmp As New FastBitmap(file, Inverser)
        Height = fBmp.Height
        Width = fBmp.Width
        Bits = fBmp.Bits
        'Bits(x + y * Width) est beaucoup plus rapide que GetPixel() avec un bitmap classique
'...
'Le reste du code utilise fortement Bits(), je ne veut pas faire à chaque fois un accès du genre fBmp.Bits()
'...
        fBmp.Dispose()
End Sub
je ne sais pas si la ligne "Bits = fBmp.Bits" créé une copie du tableau "Bits" de ma classe fBmp, ou bien si c'est une référence.

Autrement dit, est-ce que mon tableau "Dim Bits As Int32()" est copié ou bien est-ce que le tableau Bits est en fait un pointeur ? (en c++ "classique", le nom d'un tableau est un pointeur)

En VB.NET les objets sont des pointeurs, une affectation avec le signe "=" ne fait que copier la référence, pour obtenir une vraie copie il faut écrire soit même dans son objet une fonction .Clone() ou .GetCopy() et y affecter le résultat.
En revanche, dans VB.NET, avec les types de données simples (entiers, flottants, chaines de caractères), une affectation avec le signe "=" réalise une copie de la valeur ; pour avoir une référence il faut utiliser le mot clef ByRef si c'est un paramètre d'une fonction et dans les autres cas de figure ruser autrement.

C'est un des aspects de VB.NET qui ne me plait pas
Autant ça ne me dérange pas de trop qu'il n'y ai pas en VB la distinction entre "=" et "==", le "ByVal" par défaut pour les types de données classiques et le "ByRef" par défaut pour les objets est emmerdant.
Par exemple dans une fonction de calcul quand on travaille avec des angles ou des coordonnées X,Y,Z qui sont des entiers ou des flottants et en même temps des objets "points" ou "polygone" c'est vite la migraine
Je préférerait avoir deux affectations distinctes et explicites pour les copies de valeurs d'une part et pour les références d'autre part ; ça serait peut être un peu plus lourd mais plus propre et plus lisible.

Pour ne pas remettre en cause la syntaxe du langage, ça serait pas mal un mode d'affichage dans l'IDE où le signe "=" aurait une couleur différente en fonction de son sens

Merci

A bientôt