none
Définition du GetHashCode RRS feed

  • Question

  • Bonjour,

          Suite à cette question Supprimer les Doublons je souhaiterais connaitre le principe de la fonction GetHashCode.

          Après plusieurs heures à rechercher comment supprimer des doublons, il s'avère que ma fonction GetHashCode n'est pas correcte. Pouvez-vous m'expliquer ?

    Imports System.ComponentModel
    
    Public Class Form1
    
        Private MaListe As New List(Of Tortue) From {{New Tortue("Dupond", "Maurice")}, {New Tortue("Fourgheon", "Nicolas")}, {New Tortue("Fourgheon", "Thomas")}, _
                                                                                            {New Tortue("Rouch", "Nicolas")}, {New Tortue("Durand", "Maurice")}, {New Tortue("Matus", "George")}, {New Tortue("Dupond", "Gregoire")}, _
                                                                                         {New Tortue("Fayer", "Alberte")}, {New Tortue("Maurice", "Jean-Luc")}, {New Tortue("Dupond", "Aude")}, {New Tortue("Gruiter", "Aude")}}
    
    
        Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
            ListBox1.DataSource = MaListe
            Label1.Text = String.Format("{0} Personnes correspondantes...", MaListe.Count)
        End Sub
    
        Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
            ListBox1.DataSource = Nothing
            ListBox1.DataSource = MaListe.Distinct.ToList
            Label1.Text = String.Format("{0} Personnes correspondantes...", MaListe.Distinct.ToList.Count)
        End Sub
    
    End Class
    
    
    Public Class Tortue
        Implements IEquatable(Of Tortue)
    
        Public Shared Trie As Boolean = True
    
    
        Private _Id As Integer
        Private _Nom As String
        Private _Prenom As String
        Private _Age As Byte
    
        Public ReadOnly Property Identifiant() As String
            Get
                Return _Id
            End Get
        End Property
    
        Public Property Nom() As String
            Get
                Return _Nom
            End Get
            Set(ByVal value As String)
                _Nom = value
            End Set
        End Property
    
        Public Property Prenom() As String
            Get
                Return _Prenom
            End Get
            Set(ByVal value As String)
                _Prenom = value
            End Set
        End Property
    
        Public Property Age() As String
            Get
                Return _Age
            End Get
            Set(ByVal value As String)
                _Age = value
            End Set
        End Property
    
    
        Public Sub New()
            Dim Int As New Random
            _Id = Int.Next
        End Sub
    
        Public Sub New(ByVal LeNom As String, ByVal LePrenom As String)
            Dim Int As New Random
            _Id = Int.Next
            _Nom = LeNom
            _Prenom = LePrenom
        End Sub
    
        Public Overrides Function Tostring() As String
            Return _Nom & "  " & _Prenom
        End Function
    
        Public Overrides Function GetHashCode() As Integer
            Return _Id
        End Function
    
        Public Function Equals1(other As Tortue) As Boolean Implements IEquatable(Of Tortue).Equals
            Select Case True
                Case Me.Identifiant = other.Identifiant
                    Return True
                Case Me.Nom.Equals(other.Nom, StringComparison.InvariantCultureIgnoreCase)
                    Return True
                Case Me.Prenom.Equals(other.Prenom, StringComparison.InvariantCultureIgnoreCase)
                    Return True
                Case Else
                    Return False
            End Select
        End Function
    
    End Class
    Merci d'avance


    Boby15000

    dimanche 30 août 2015 22:04

Réponses

  • Bonjour,

    dans votre cas, les doublons généré par getHashCode viennent du fait que votre variable _id est random.

    Il ne faut pas se fier au hasard pour généré le hash code mais par exemple d'un ensemble nom - prenom - age (qui limite le risque de doublon bien que cela soit possible)

    exemple:

    Public Overrides Function GetHashCode() As Integer
            Return _Nom.GetHashCode() + Prenom.GetHashCode() + Age.GetHashCode()
        End Function

    Cordialement

    Cedric

    lundi 31 août 2015 06:37
  • Bonjour,

    Pour résumer sans faire de long discours, votre classe pourrait ressembler à cela :

    Public Class Tortue
        Implements IEquatable(Of Tortue)
        public Property Nom as String
        Public Property Prenom As String  
        Public Property Age As String
    
        Public Sub New(nomA As String, prenomA As String)
            Nom = nomA
            Prenom = prenomA
        End Sub
    
        Public Overrides Function Tostring() As String
            If Nom IsNot Nothing AndAlso Prenom IsNot Nothing Then 
                Return String.Format("{0} {1}", Nom, Prenom)
            End If
            return MyBase.ToString()
        End Function
    
    
        Public Overloads Function Equals(other As Tortue) As Boolean Implements IEquatable(Of Tortue).Equals
            If ReferenceEquals(Nothing, other) Then Return False
            If ReferenceEquals(Me, other) Then Return True
            Return String.Equals(Nom, other.Nom) AndAlso String.Equals(Prenom, other.Prenom) AndAlso String.Equals(Age, other.Age)
        End Function
    
        Public Overloads Overrides Function Equals(obj As Object) As Boolean
            If ReferenceEquals(Nothing, obj) Then Return False
            If ReferenceEquals(Me, obj) Then Return True
            If obj.GetType IsNot Me.GetType Then Return False
            Return Equals(DirectCast(obj, Tortue))
        End Function
    
        Public Overrides Function GetHashCode() As Integer
            Dim hashCode = 0
            If Nom IsNot Nothing Then
                hashCode = Nom.GetHashCode
            End If
            If Prenom IsNot Nothing Then
                hashCode = CInt((hashCode*397L) Mod Integer.MaxValue) Xor Prenom.GetHashCode
            End If
            If Age IsNot Nothing Then
                hashCode = CInt((hashCode*397L) Mod Integer.MaxValue) Xor Age.GetHashCode
            End If
            Return hashCode
        End Function
    End Class

    (généré avec ReSharper et j'ai fais quelques retouches)


    Richard Clark
    Consultant - Formateur .NET
    http://www.c2i.fr
    Depuis 1996: le 1er site .NET francophone

    lundi 31 août 2015 07:10
  • Bonjour,

    Pour compléter la réponse de Richard, GetHashCode() est fait pour générer une valeur de hash du contenu d'un objet, ce qui permet d'optimiser l'égalité entre objets.

    Deux objets de même "contenu" doivent retourner le même hash code (c'est la seule obligation dans son implémentation). Mais un hash code peut correspondre à plusieurs objets différents.

    L'utilité dans des objets .Net réside dans l'optimisation du calcul de l'égalité entre objets, par exemple si nous devons comparer 2 chaînes de caractères qui font 1000 caractères chacune, avant de faire ce test qui sera lourd, on va tester si les hash codes sont identiques, si ce n'est pas le cas de sur les chaînes ne correspondent pas donc pas besoin de faire le test d'égalité.

    C'est utilisé dans les HashTable, Dictionnaire et autre collections basée sur un index pour facilité l'égalité des clés et la répartition des éléments dans des arbres.

    Cordialement,


    Yan Grenier

    Merci de bien vouloir "Marquer comme réponse", les réponses qui ont répondues à votre question, et de noter les réponses que vous avez trouvé utiles.

    lundi 31 août 2015 12:14

Toutes les réponses

  • Bonjour,

    dans votre cas, les doublons généré par getHashCode viennent du fait que votre variable _id est random.

    Il ne faut pas se fier au hasard pour généré le hash code mais par exemple d'un ensemble nom - prenom - age (qui limite le risque de doublon bien que cela soit possible)

    exemple:

    Public Overrides Function GetHashCode() As Integer
            Return _Nom.GetHashCode() + Prenom.GetHashCode() + Age.GetHashCode()
        End Function

    Cordialement

    Cedric

    lundi 31 août 2015 06:37
  • Bonjour,

          Suite à votre réponse, je reviens à mon sujet initiale :

          A l'aide d'une bindinglist(of Bouteille), je charge différents combobox de cette manière.

       Cb_Etiquette_Historique.DataSource = DGW_Historique.DataSource
            Cb_Etiquette_Historique.DisplayMember = "Etiquette"
    
            Cb_Millesime_Historique.DataSource = DGW_Historique.DataSource
            Cb_Millesime_Historique.DisplayMember = "Millesime"
    
            Cb_Region_Historique.DataSource = DGW_Historique.DataSource
            Cb_Region_Historique.DisplayMember = "Region"
    
            Cb_Couleur_Historique.DataSource = DGW_Historique.DataSource
            Cb_Couleur_Historique.DisplayMember = "Couleur"

           Les combobox sont parfaitement bien chargé. Cependant je me retrouve avec des doublons (exemple dans la liste des millésimes, j'ai plusieurs fois l'année 2013. En dehors du contexte des combobox, cela est parfaitement normale. Plusieurs bouteilles de vin peut-être de la même année sans pour autant être identique.

    Mon but est donc de supprimer les doublons uniquement sur les combobox. Ceux-ci servant à la recherche. Exemple , je peux rechercher toutes les bouteilles de 2013 (inutile d'avoir plusieurs fois l'année 2013 dans les items).

    Merci d'avance....


    Boby15000


    • Modifié Boby15000 lundi 31 août 2015 06:49
    lundi 31 août 2015 06:48
  • Bonjour Boby15000,

    Je vous avais indiqué d'utiliser la méthode Distinct (Linq). Avez-vous eu un problème particulier avec son implémentation ?

    Voici un exemple qui devrait vous permettre de vous en sortir : Distinct . Si ce n'est pas le cas, revenez présenter votre code, nous allons vous aider.

    lundi 31 août 2015 07:09
  • Bonjour,

    Pour résumer sans faire de long discours, votre classe pourrait ressembler à cela :

    Public Class Tortue
        Implements IEquatable(Of Tortue)
        public Property Nom as String
        Public Property Prenom As String  
        Public Property Age As String
    
        Public Sub New(nomA As String, prenomA As String)
            Nom = nomA
            Prenom = prenomA
        End Sub
    
        Public Overrides Function Tostring() As String
            If Nom IsNot Nothing AndAlso Prenom IsNot Nothing Then 
                Return String.Format("{0} {1}", Nom, Prenom)
            End If
            return MyBase.ToString()
        End Function
    
    
        Public Overloads Function Equals(other As Tortue) As Boolean Implements IEquatable(Of Tortue).Equals
            If ReferenceEquals(Nothing, other) Then Return False
            If ReferenceEquals(Me, other) Then Return True
            Return String.Equals(Nom, other.Nom) AndAlso String.Equals(Prenom, other.Prenom) AndAlso String.Equals(Age, other.Age)
        End Function
    
        Public Overloads Overrides Function Equals(obj As Object) As Boolean
            If ReferenceEquals(Nothing, obj) Then Return False
            If ReferenceEquals(Me, obj) Then Return True
            If obj.GetType IsNot Me.GetType Then Return False
            Return Equals(DirectCast(obj, Tortue))
        End Function
    
        Public Overrides Function GetHashCode() As Integer
            Dim hashCode = 0
            If Nom IsNot Nothing Then
                hashCode = Nom.GetHashCode
            End If
            If Prenom IsNot Nothing Then
                hashCode = CInt((hashCode*397L) Mod Integer.MaxValue) Xor Prenom.GetHashCode
            End If
            If Age IsNot Nothing Then
                hashCode = CInt((hashCode*397L) Mod Integer.MaxValue) Xor Age.GetHashCode
            End If
            Return hashCode
        End Function
    End Class

    (généré avec ReSharper et j'ai fais quelques retouches)


    Richard Clark
    Consultant - Formateur .NET
    http://www.c2i.fr
    Depuis 1996: le 1er site .NET francophone

    lundi 31 août 2015 07:10
  • Tout d'abord merci pour vos réponses. Néanmoins quelques choses me rends perplexe. A quoi sert exactement la fonction "GetHashCode". Le contrôle d'égalité se fait via la fonction "Equals".... Aucunes variables "integer" venant de GetHashCode est utilisé dans la fonction "Equals", autrement dit la simple fonction Equals devrait suffir :

        Public Overloads Function Equals(other As Tortue) As Boolean Implements IEquatable(Of Tortue).Equals
            If ReferenceEquals(Nothing, other) Then Return False
            If ReferenceEquals(Me, other) Then Return True
            Return String.Equals(Nom, other.Nom) AndAlso String.Equals(Prenom, other.Prenom) AndAlso String.Equals(Age, other.Age)
        End Function

    ou

    Public Function Equals1(other As Tortue) As Boolean Implements IEquatable(Of Tortue).Equals
            Select Case True
                Case Me.Identifiant = other.Identifiant
                    Return True
                Case Me.Nom.Equals(other.Nom, StringComparison.InvariantCultureIgnoreCase)
                    Return True
                Case Me.Prenom.Equals(other.Prenom, StringComparison.InvariantCultureIgnoreCase)
                    Return True
                Case Else
                    Return False
            End Select
        End Function

    Ces deux fonctions sont très claire. Elle compare et retourne le résultat de la comparaison... A quel moment le HashCode rentre en jeux... C'est là que je suis perdu....

    Merci d'avance.....

    Je suis un débutant....


    Boby15000

    lundi 31 août 2015 10:34
  • Le GetHashCode peut être utilisé par certaines classes du Framework.

    Cette méthode existe depuis le Framework 1.0, ce qui n'est pas le cas de Equatable.

    C'est donc plus prudent de l'implémenter.


    Richard Clark
    Consultant - Formateur .NET
    http://www.c2i.fr
    Depuis 1996: le 1er site .NET francophone

    lundi 31 août 2015 11:50
  • Bonjour,

    Pour compléter la réponse de Richard, GetHashCode() est fait pour générer une valeur de hash du contenu d'un objet, ce qui permet d'optimiser l'égalité entre objets.

    Deux objets de même "contenu" doivent retourner le même hash code (c'est la seule obligation dans son implémentation). Mais un hash code peut correspondre à plusieurs objets différents.

    L'utilité dans des objets .Net réside dans l'optimisation du calcul de l'égalité entre objets, par exemple si nous devons comparer 2 chaînes de caractères qui font 1000 caractères chacune, avant de faire ce test qui sera lourd, on va tester si les hash codes sont identiques, si ce n'est pas le cas de sur les chaînes ne correspondent pas donc pas besoin de faire le test d'égalité.

    C'est utilisé dans les HashTable, Dictionnaire et autre collections basée sur un index pour facilité l'égalité des clés et la répartition des éléments dans des arbres.

    Cordialement,


    Yan Grenier

    Merci de bien vouloir "Marquer comme réponse", les réponses qui ont répondues à votre question, et de noter les réponses que vous avez trouvé utiles.

    lundi 31 août 2015 12:14
  • Je vous remercie pour vos réponse une fois encore. De ce faite revenons sur mon problème de base. Soit le code suivant :

    Public Class Form1
    
        Private MaListe As New List(Of Tortue) From {{New Tortue("Dupond", "Maurice")}, {New Tortue("Fourgheon", "Nicolas")}, {New Tortue("Fourgheon", "Thomas")}, _
                                                                                            {New Tortue("Rouch", "Nicolas")}, {New Tortue("Durand", "Maurice")}, {New Tortue("Matus", "George")}, {New Tortue("Dupond", "Gregoire")}, _
                                                                                         {New Tortue("Fayer", "Alberte")}, {New Tortue("Maurice", "Jean-Luc")}, {New Tortue("Dupond", "Aude")}, {New Tortue("Gruiter", "Aude")}}
    
    
        Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
            ListBox1.DataSource = MaListe
            ComboBox1.DataSource = MaListe.Distinct.ToList
            ComboBox1.DisplayMember = "Nom"
            ComboBox2.DataSource = MaListe.Distinct.ToList
            ComboBox2.DisplayMember = "Prenom"
            Label1.Text = String.Format("{0} Personnes correspondantes...", MaListe.Count)
        End Sub
    
        Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
            ListBox1.DataSource = Nothing
            ListBox1.DataSource = MaListe.Distinct.ToList
            Label1.Text = String.Format("{0} Personnes correspondantes...", MaListe.Distinct.ToList.Count)
        End Sub
    
    End Class
    
    
    Public Class Tortue
        Implements IEquatable(Of Tortue)
    
        Private _Id As Integer
        Private _Nom As String
        Private _Prenom As String
        Private _Age As Byte
    
        Public ReadOnly Property Identifiant() As String
            Get
                Return _Id
            End Get
        End Property
    
        Public Property Nom() As String
            Get
                Return _Nom
            End Get
            Set(ByVal value As String)
                _Nom = value
            End Set
        End Property
    
        Public Property Prenom() As String
            Get
                Return _Prenom
            End Get
            Set(ByVal value As String)
                _Prenom = value
            End Set
        End Property
    
        Public Property Age() As String
            Get
                Return _Age
            End Get
            Set(ByVal value As String)
                _Age = value
            End Set
        End Property
    
    
        Public Sub New()
            Dim Int As New Random
            _Id = Int.Next
        End Sub
    
        Public Sub New(ByVal LeNom As String, ByVal LePrenom As String)
            Dim Int As New Random
            _Id = Int.Next
            _Nom = LeNom
            _Prenom = LePrenom
        End Sub
    
        Public Overrides Function Tostring() As String
            Return _Nom
        End Function
    
        Public Overloads Function Equals(other As Tortue) As Boolean Implements IEquatable(Of Tortue).Equals
            If ReferenceEquals(Nothing, other) Then Return False
            If ReferenceEquals(Me, other) Then Return True
            Return String.Equals(Nom, other.Nom) AndAlso String.Equals(Prenom, other.Prenom) AndAlso String.Equals(Age, other.Age)
        End Function
    
        Public Overloads Overrides Function Equals(obj As Object) As Boolean
            If ReferenceEquals(Nothing, obj) Then Return False
            If ReferenceEquals(Me, obj) Then Return True
            If obj.GetType IsNot Me.GetType Then Return False
            Return Equals(DirectCast(obj, Tortue))
        End Function
    
        Public Overrides Function GetHashCode() As Integer
            Dim hashCode = 0
            If Nom IsNot Nothing Then
                hashCode = Nom.GetHashCode
            End If
            If Prenom IsNot Nothing Then
                hashCode = CInt((hashCode * 397L) Mod Integer.MaxValue) Xor Prenom.GetHashCode
            End If
            If Age IsNot Nothing Then
                hashCode = CInt((hashCode * 397L) Mod Integer.MaxValue) Xor Age.GetHashCode
            End If
            Return hashCode
        End Function
    
    End Class

           Pouvez-vous m'expliquer pourquoi les combobox contiennent toujours des doublons. C'est là le plus gros de mon problème....

    Merci beaucoup pour votre partage...


    Boby15000

    lundi 31 août 2015 12:48
  • Bonsoir,

    Votre méthode GetHashCode examine le nom, prénom et age. Or dans votre liste, il n'y a pas 2 éléments dont les valeurs de nom et prénom (vous n'utilisez pas age) soient semblables. Par conséquent, le hash code est différent pour chaque élément.

    Dans votre première combobox, vous voulez afficher les noms sans les doublons et dans votre seconde les prénoms sans les doublons. Dans ce cas, il faut utiliser la méthode distinct surchargée avec un comparer. Regardez donc la méthode Distinct surchargée dans la documentation : Distinct

    Vous devrez créer 2 comparers, un pour le nom et un pour le prénom.

    lundi 31 août 2015 20:28
  • Bonsoir,

           Je viens de réussir sur ma "class" de test, cependant sur mon programme de base cela ne fonctionne pas.

    Public Class TypeBouteille
        Implements System.ComponentModel.INotifyPropertyChanged
    
        Private Const TOLERANCE_TEMPS_DE_GARDE_MAX As UShort = 10
        Private Const PRIX_MAX As UShort = 150
    
        Private Shared _Millesime_De_Depart As UShort = CUShort(Date.Now.Year - 15)
        Private Shared _Millesime_De_Fin As UShort = CUShort(Date.Now.Year)
        Private Shared _ListeImage As New List(Of Image) From {My.Resources.Mauvais, My.Resources.Etoile1, My.Resources.Etoile2, My.Resources.Etoile3}
        Private Shared _IdentifiantUnique As New Random
        Public Shared ReadOnly CouleursDeBase As New List(Of String) From {"BLANC DOUX", "BLANC SEC", "ROUGE", "ROSE", "PETILLANT"}
        Public Shared ReadOnly ListeDesNotes As New List(Of Integer) From {-1, 0, 1, 2, 3}
    
        Private _Identifiant As Integer = -1
        Private _Etiquette As String
        Private _Couleur As String
        Private _Region As String
        Private _Millesime As UShort = Date.Now.Year
        Private _LesAccompagnements As New List(Of String)
        Private _Observation As String = String.Empty
        Private _LesCasiers As New List(Of String)
        Private _LesSorties As New List(Of Date)
        Private _TempsDeGarde As Byte = 0
        Private _Tolerance As Byte = 0
        Private _Prix As Byte = 0
        Private _Note As Integer = -1
    
        Private WithEvents MyTymer As New Timer
    
        Public Event PropertyChanged(sender As Object, e As System.ComponentModel.PropertyChangedEventArgs) Implements System.ComponentModel.INotifyPropertyChanged.PropertyChanged
    
    
        ''' <summary>
        ''' Obtiens la légende correspondant à la couleur.
        ''' </summary>
        ''' <param name="Obj">Objet Color</param>
        Public Shared Function Legende(Obj As Color) As String
            Select Case Obj
                Case Color.Green
                    Return "Bouteille Disponible"
                Case Color.Red
                    Return "Bouteille en Attente"
                Case Color.Black
                    Return "Bouteille à Consommer"
                Case Else
                    Return String.Empty
            End Select
        End Function
    
        Public Shared Function CouleurEtat() As List(Of Color)
            Return New List(Of Color) From {Color.Red, Color.Green, Color.Black}
        End Function
    
        Public Shared Function CouleurString() As Dictionary(Of Color, String)
            Return New Dictionary(Of Color, String) From {{Color.Red, "En Attente"}, {Color.Green, "Disponible"}, {Color.Black, "A  Consommer"}}
        End Function
    
        Public Shared Function Millesimes() As List(Of UShort)
            Dim LesMillesimes As New List(Of UShort)
            For Depart = _Millesime_De_Depart To _Millesime_De_Fin Step 1
                LesMillesimes.Add(Depart)
            Next
            Return LesMillesimes
        End Function
    
        Public Shared Function TempsDeGarde_Tolerance() As List(Of Byte)
            Dim LeTempsDeGarde_Tolerance As New List(Of Byte)
            For Depart = 0 To TOLERANCE_TEMPS_DE_GARDE_MAX Step 1
                LeTempsDeGarde_Tolerance.Add(Depart)
            Next
            Return LeTempsDeGarde_Tolerance
        End Function
    
        Public Shared Function Tarifs() As List(Of Byte)
            Dim LePrix As New List(Of Byte)
            For Depart = 0 To PRIX_MAX Step 1
                LePrix.Add(Depart)
            Next
            Return LePrix
        End Function
    
        ''' <summary>
        ''' Obtiens ou Détermine l'Identifiant de la Bouteille.
        ''' </summary>
        Public ReadOnly Property Identifiant() As Integer
            Get
                Return _Identifiant
            End Get
        End Property
    
        ''' <summary>
        ''' Obtiens les dates de sorties de ce type de Bouteille.
        ''' </summary>
        Public ReadOnly Property LesSorties() As List(Of Date)
            Get
                Return _LesSorties
            End Get
        End Property
    
        ''' <summary>
        ''' Obtiens le Nombre sorties de ce type de Bouteille.
        ''' </summary>
        Public ReadOnly Property NbrDeSorties() As Integer
            Get
                Return _LesSorties.Count
            End Get
        End Property
    
        ''' <summary>
        ''' Obtiens ou Détermine l'Etiquette de la Bouteille.
        ''' </summary>
        Public Property Etiquette() As String
            Get
                Return _Etiquette
            End Get
            Set(value As String)
                If String.IsNullOrWhiteSpace(value) Then Throw New ArgumentException("Veuillez renseigner l'étiquette.")
                _Etiquette = value.ToUpper.Trim
                RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs("Etiquette"))
            End Set
        End Property
    
        ''' <summary>
        ''' Obtiens ou Détermine la Couleur de la Bouteille.
        ''' </summary>
        Public Property Couleur() As String
            Get
                Return _Couleur
            End Get
            Set(value As String)
                If String.IsNullOrWhiteSpace(value) Then Throw New ArgumentException("Veuillez renseigner la Couleur du vin.")
                _Couleur = value.ToUpper.Trim
                RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs("Couleur"))
            End Set
        End Property
    
        ''' <summary>
        ''' Obtiens ou Détermine la Region de la Bouteille.
        ''' </summary>
        Public Property Region() As String
            Get
                Return _Region
            End Get
            Set(value As String)
                If String.IsNullOrWhiteSpace(value) Then Throw New ArgumentException("Veuillez renseigner la Région du vin.")
                _Region = value.ToUpper.Trim
                RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs("Region"))
            End Set
        End Property
    
        ''' <summary>
        ''' Obtiens ou Détermine le Millesime de la Bouteille.
        ''' </summary>
        Public Property Millesime() As UShort
            Get
                Return _Millesime
            End Get
            Set(value As UShort)
                If value < _Millesime_De_Depart Or value > _Millesime_De_Fin Then Throw New ArgumentException("Le Millésime est hors Plage.")
                _Millesime = value
                RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs("Millesime"))
            End Set
        End Property
    
        ''' <summary>
        ''' Obtiens la liste des Accompagnements de la Bouteille.
        ''' </summary>
        <XmlArray("Accompagnements")>
        <XmlArrayItem("Accompagnement")>
        Public ReadOnly Property LesAccompagnements() As List(Of String)
            Get
                Return _LesAccompagnements
            End Get
        End Property
    
        ''' <summary>
        ''' Obtiens ou Détermine l'Observation de la Bouteille.
        ''' </summary>
        Public Property Observation() As String
            Get
                Return _Observation
            End Get
            Set(value As String)
                _Observation = value
                RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs("Observation"))
            End Set
        End Property
    
        ''' <summary>
        ''' Obtiens la liste des Casiers de ce type de Bouteille.
        ''' </summary>
        <XmlArray("Casiers")>
        <XmlArrayItem("Casier")>
        Public ReadOnly Property LesCasiers() As List(Of String)
            Get
                Return _LesCasiers
            End Get
        End Property
    
        ''' <summary>
        ''' Obtiens la liste des Casiers de ce type de Bouteille.
        ''' </summary>
        Public ReadOnly Property LesCasiersString() As String
            Get
                Dim LesCasiersToString As String = String.Empty
                For Each Casier As String In _LesCasiers
                    LesCasiersToString &= Casier & " ; "
                Next
                Return LesCasiersToString.Trim.Remove(LesCasiersToString.Trim.Length - 1, 1)
            End Get
        End Property
    
        ''' <summary>
        ''' Obtiens ou Détermine le Temps de Garde de la Bouteille.
        ''' </summary>
        Public Property TempsDeGarde() As Byte
            Get
                Return _TempsDeGarde
            End Get
            Set(value As Byte)
                If value < 0 Then Throw New ArgumentException("Le Temps de garde ne peut être négatif")
                _TempsDeGarde = value
                RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs("TempsDeGarde"))
            End Set
        End Property
    
        ''' <summary>
        ''' Obtiens ou Détermine la Tolérance.
        ''' </summary>
        Public Property Tolerance() As Byte
            Get
                Return _Tolerance
            End Get
            Set(value As Byte)
                If value < 0 Then Throw New ArgumentException("La Tolérance ne peut être négatif")
                _Tolerance = value
                RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs("Tolerance"))
            End Set
        End Property
    
        ''' <summary>
        ''' Obtiens ou Détermine le Prix de la Bouteille.
        ''' </summary>
        Public Property Prix() As Byte
            Get
                Return _Prix
            End Get
            Set(value As Byte)
                If value < 0 Then Throw New ArgumentException("Le Prix ne peut être négatif")
                _Prix = value
                RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs("Prix"))
            End Set
        End Property
    
        ''' <summary>
        ''' Obtiens ou Détermine la Note de la Bouteille.
        ''' </summary>
        Public Property Note() As Integer
            Get
                Return _Note
            End Get
            Set(ByVal value As Integer)
                If IsNothing(value) Or value > 3 Then Throw New ArgumentException("Veuillez renseigner la note.")
                _Note = value
                RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs("Note"))
            End Set
        End Property
    
        ''' <summary>
        ''' Obtiens l'équivalent de la Note de la Bouteille en image.
        ''' </summary>
        Public ReadOnly Property NoteImage() As Image
            Get
                If _Note < 0 Then Return My.Resources.Inconnu
                Return _ListeImage.Item(_Note)
            End Get
        End Property
    
        ''' <summary>
        ''' Obtiens le Nombre de ce Type de Bouteille.
        ''' </summary>
        Public ReadOnly Property EnStock() As Integer
            Get
                Return _LesCasiers.Count
            End Get
        End Property
    
        ''' <summary>
        ''' Obtiens l'état de la Bouteille.
        ''' </summary>
        Public ReadOnly Property Status() As Color
            Get
                If (_Millesime + _TempsDeGarde) > Date.Now.Year Then
                    Return Color.Red
                ElseIf (_Millesime + _TempsDeGarde + _Tolerance) <= Date.Now.Year Then
                    Return Color.Black
                Else
                    Return Color.Green
                End If
            End Get
        End Property
    
    
    
        ''' <summary>
        ''' Crée une Nouvelle Bouteille.
        ''' </summary>
        Public Sub New()
            _Identifiant = _IdentifiantUnique.Next
            MyTymer.Interval = 5000
            MyTymer.Start()
        End Sub
    
        ''' <summary>
        ''' Ajoute un Accompagnement à la liste.
        ''' </summary>
        ''' <param name="NomDeAccompagnement">Nom de l'accompagnement</param>
        Public Sub Ajouter_Accompagnement(ByVal NomDeAccompagnement As String)
            If String.IsNullOrWhiteSpace(NomDeAccompagnement) Then Exit Sub
            If Not Est_Accompagnement(NomDeAccompagnement.Trim.ToUpper) Then
                _LesAccompagnements.Add(NomDeAccompagnement.Trim.ToUpper)
                RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs("LesAccompagnements"))
            End If
        End Sub
    
        ''' <summary>
        ''' Supprime un Accompagnement de la liste.
        ''' </summary>
        ''' <param name="NomDeAccompagnement">Nom de l'accompagnement</param>
        Public Sub Supprimer_Accompagnement(ByVal NomDeAccompagnement As String)
            If String.IsNullOrWhiteSpace(NomDeAccompagnement) Then Exit Sub
            If Est_Accompagnement(NomDeAccompagnement.Trim.ToUpper) Then
                _LesAccompagnements.Remove(NomDeAccompagnement.Trim.ToUpper)
                RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs("LesAccompagnements"))
            End If
        End Sub
    
        ''' <summary>
        ''' Détermine si l'accompagnement spécifié fait partie de la liste
        ''' </summary>
        Public Function Est_Accompagnement(Accompagnement As String) As Boolean
            Return _LesAccompagnements.Contains(Accompagnement)
        End Function
    
        ''' <summary>
        ''' Détermine si l'accompagnement spécifié fait partie de la liste
        ''' </summary>
        Public Function Est_Accompagnement(ByVal ListeAccompagnements As List(Of String)) As Boolean
            Dim Resultat As Boolean = False
            For Each UnAccompagnement As String In ListeAccompagnements
                Resultat = _LesAccompagnements.Contains(UnAccompagnement)
            Next
            Return Resultat
        End Function
    
         
        Public Sub Clear_Accompagnement()
            _LesAccompagnements.Clear()
            RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs("LesAccompagnements"))
        End Sub
    
        ''' <summary>
        ''' Ajoute le Casier spécifié à la liste.
        ''' </summary>
        ''' <param name="NomDuCasier">Nom du Casier</param>
        Public Sub Ajouter_Casier(ByVal NomDuCasier As String)
            If String.IsNullOrWhiteSpace(NomDuCasier) Then Exit Sub
            If Est_Presente(NomDuCasier) Then Throw New IndexOutOfRangeException("Ce casier est déjà utilisé.")
            If Not Est_Presente(NomDuCasier) Then
                _LesCasiers.Add(NomDuCasier)
                RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs("LesCasiers"))
            End If
        End Sub
    
        ''' <summary>
        ''' Supprime le Casier spécifié de la liste.
        ''' </summary>
        ''' <param name="NomDuCasier">Nom du Casier</param>
        Public Sub Supprimer_Casier(ByVal NomDuCasier As String)
            If String.IsNullOrWhiteSpace(NomDuCasier) Then Throw New ArgumentException("Veuillez préciser le Casier à retirer.")
            If Not Est_Presente(NomDuCasier) Then Throw New IndexOutOfRangeException("Cette Bouteille n'est pas contenu dans ce Casier.")
            If _LesCasiers.Remove(NomDuCasier) Then _LesSorties.Add(Date.Now)
            RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs("LesCasiers"))
            ' Comment peut-on supprimer un casier :
            ' Depuis l'interface "sortir" ou "couper"
        End Sub
    
        ''' <summary>
        ''' Détermine la présence de la Bouteille dans le Casier spécifié.
        ''' </summary>
        Public Function Est_Presente(ByVal NomDuCasier As String) As Boolean
            Return _LesCasiers.Contains(NomDuCasier)
        End Function
    
        ''' <summary>
        ''' Vide le Stock.
        ''' </summary>
        Public Sub Clear()
            _LesCasiers.ForEach(Sub(UnElement) _LesSorties.Add(Date.Now))
            _LesCasiers.Clear()
            RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs("LesCasiers"))
        End Sub
    
        ''' <summary>
        ''' Détermine la disponibilité de la Bouteille.
        ''' </summary>
        Public Function Est_Disponible() As Boolean
            If (_Millesime + _TempsDeGarde) > Date.Now.Year Then
                Return False
            ElseIf (_Millesime + _TempsDeGarde + _Tolerance) <= Date.Now.Year Then
                Return True
            Else
                Return True
            End If
        End Function
    
        ''' <summary>
        ''' Retourne la surcharge du ToString de la Bouteille.
        ''' </summary>
        Public Overrides Function ToString() As String
            Return String.Format("{0} de {1}, ({2}, {3})", _Etiquette, _Millesime, _Region, _Couleur)
        End Function
    
    
        Private Sub MAJ_DesSortie()
            ' Supprime toutes les dates supérieur à un an.
            _LesSorties.RemoveAll(Function(UneDateDeSortie) (DateDiff(DateInterval.Day, Now, UneDateDeSortie) >= 365))
            MyTymer.Stop()
        End Sub
    
        'Public Function GetHashCode1(obj As TypeBouteille) As Integer Implements IEqualityComparer(Of TypeBouteille).GetHashCode
        '    Return obj.Identifiant
        'End Function
    
        'Public Function Equals1(x As TypeBouteille, y As TypeBouteille) As Boolean Implements IEqualityComparer(Of TypeBouteille).Equals
        '    If x.Identifiant = y.Identifiant Then
        '        Return True
        '    ElseIf x.Etiquette = y.Etiquette AndAlso x.Couleur = x.Couleur AndAlso x.Region = y.Region AndAlso x.Millesime = y.Millesime Then
        '        Return True
        '    Else
        '        Return False
        '    End If
        '    Return (x.Identifiant = y.Identifiant)
        'End Function
    
    
        Private Sub _MyTymer_Ticks(sender As Object, e As EventArgs) Handles MyTymer.Tick
            If _LesSorties.Count = 0 Then Exit Sub
            MAJ_DesSortie()
        End Sub
    
    End Class
    
    
    Public Class ComparerByEtiquette
        Implements IEqualityComparer(Of TypeBouteille)
    
        Public Function Equals1(x As TypeBouteille, y As TypeBouteille) As Boolean Implements IEqualityComparer(Of TypeBouteille).Equals
            Return String.Equals(x.Etiquette, y.Etiquette)
        End Function
    
        Public Function GetHashCode1(obj As TypeBouteille) As Integer Implements IEqualityComparer(Of TypeBouteille).GetHashCode
            Return obj.Etiquette.GetHashCode
        End Function
    
    End Class
    
    Public Class ComparerByMillesime
        Implements IEqualityComparer(Of TypeBouteille)
    
        Public Function Equals1(x As TypeBouteille, y As TypeBouteille) As Boolean Implements IEqualityComparer(Of TypeBouteille).Equals
            Return (x.Millesime = y.Millesime)
        End Function
    
        Public Function GetHashCode1(obj As TypeBouteille) As Integer Implements IEqualityComparer(Of TypeBouteille).GetHashCode
            Return obj.Millesime.GetHashCode
        End Function
    
    End Class
    
        Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    
            ' Charge les Contrôles et leurs attribuent l'évenement Click et Double Click.
            For Each Controle In Panel1.Controls
                If TypeOf Controle Is Panel Then
                    Dim MyPanel As Panel = CType(Controle, Panel)
                    MyPanel.BackgroundImageLayout = ImageLayout.Stretch
                    MyPanel.BackColor = Color.Gainsboro
                    MyPanel.ContextMenuStrip = CliqueDroit
                    AddHandler MyPanel.Click, AddressOf Panel_Click
                    AddHandler MyPanel.DoubleClick, AddressOf Panel_DoubleClick
                End If
            Next
    
            '---- Partie : "Recherche" ----
            DGW_Resultats.AutoGenerateColumns = False
            Cb_Couleur_Recherche.DataSource = _MaCave.Couleurs
            Cb_Region_Recherche.DataSource = _MaCave.Regions
            Clb_Accompagnement_Recherche.DataSource = _MaCave.Accompagnements
            Cb_Disponibilite.DataSource = TypeBouteille.CouleurEtat
            Cb_Disponibilite.DrawMode = DrawMode.OwnerDrawFixed
    
            '---- Partie : "Edition" ----
            Cb_Couleur_Ajout.DataSource = _MaCave.Couleurs
            Cb_Region_Ajout.DataSource = _MaCave.Regions
            Cb_Millesime_Ajout.DataSource = TypeBouteille.Millesimes()
            Clb_Accompagnement_Ajout.DataSource = _MaCave.Accompagnements
            Cb_TempsDeGarde_Ajout.DataSource = TypeBouteille.TempsDeGarde_Tolerance()
            Cb_Tolerance_Ajout.DataSource = TypeBouteille.TempsDeGarde_Tolerance()
            Cb_Prix_Ajout.DataSource = TypeBouteille.Tarifs()
    
            '---- Partie : "Options" ----
            Lb_Regions_Options.DataSource = _MaCave.Regions
            Lb_Accompagnements_Options.DataSource = _MaCave.Accompagnements
    
            '---- Partie : "Coin Du Caviste" ----
            DGW_Historique.ShowCellToolTips = True
            DGW_Historique.AutoGenerateColumns = False
            DGW_Historique.DataSource = _MaCave.Bouteilles
    
            Cb_Etiquette_Historique.DataSource = New BindingList(Of TypeBouteille)(_MaCave.Bouteilles.Distinct(New ComparerByEtiquette).ToList)
            Cb_Etiquette_Historique.DisplayMember = "Etiquette"
    
            Cb_Millesime_Historique.DataSource = New BindingList(Of TypeBouteille)(_MaCave.Bouteilles.Distinct(New ComparerByMillesime).ToList)
            Cb_Millesime_Historique.DisplayMember = "Millesime"
    
            Cb_Region_Historique.DataSource = DGW_Historique.DataSource
            Cb_Region_Historique.DisplayMember = "Region"
    
            Cb_Couleur_Historique.DataSource = DGW_Historique.DataSource
            Cb_Couleur_Historique.DisplayMember = "Couleur"
    
            Cb_Qualite_Historique.DrawMode = DrawMode.OwnerDrawVariable
            Cb_Qualite_Historique.DataSource = DGW_Historique.DataSource
            Cb_Qualite_Historique.DisplayMember = "NoteImage"
    
            ListeDesBouteillesModifie()
    
        End Sub
    

    Voilà, j'ai fait de la même manière que sur ma "Class" de base mais ça ne fonctionne pas.

    Merci pour votre aide....


    Boby15000

    lundi 31 août 2015 21:32
  • Je relance mon post.. Ayant toujours des difficultés au niveau de mon code, je reviens demander votre aide...

    Merci à vous...


    Boby15000

    jeudi 3 septembre 2015 17:55