Bonjour Madame, Monsieur
Ayant réalisé quelques classes personnelles, j'aimerais maintenant les doter du For…Each, mais je ne sais comment m'y prendre. Quelqu'un pourrais-t-il m'aider ?
Merci d'avance.
Bonjour Madame, Monsieur
Ayant réalisé quelques classes personnelles, j'aimerais maintenant les doter du For…Each, mais je ne sais comment m'y prendre. Quelqu'un pourrais-t-il m'aider ?
Merci d'avance.
Salut,
Que veux-tu faire exactement ? Qu'entends-tu par "les doter du For Each" ?
Si le but est de pouvoir "parcourir" la classe avec un boucle For Each, il faut implémenter l'interface IEnumerable, ou sa version générique IEnumerable(Of T)
Pas de questions techniques par MP ! Le forum est là pour ça...
Tutoriels : Les nouveautés de C# 6 - Accès aux données avec Dapper - Extraction de données de pages web à l'aide de HTML Agility Pack - La sérialisation XML avec .NET (Aller plus loin) - Les markup extensions en WPF
Ça c'est juste un cas particulier des pré-requis nécessaires.
Pour pouvoir faire un For Each, il faut:
- Une méthode d'instance GetEnumerator qui retourne un type "Iterable"
- Ce type Iterable doit posséder:
- Une propriété Current qui doit retourner le type sur lequel on boucle (ou un type convertible en celui sur lequel on boucle)
- Une méthode MoveNext qui renvoie un Boolean (True tant q'uon peut itérer)
Voici un exemple simpliste pour illustrerAprès on peut se contenter de juste faire une méthode GetEnumerator qui renvoie un items.GetEnumerator sans forcément implémenter toute l'interface.
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 Public Class CustomClass Private items As Integer() Public Sub New() items = {42, 666, 1234, 0, -42} End Sub Public Function GetEnumerator() As CustomClassEnumerator Return New CustomClassEnumerator(Me) End Function ' Représente le type Iterable évoqué dans l'explication Public Class CustomClassEnumerator Private index As Integer Private source As CustomClass Public Sub New(ByVal src As CustomClass) index = -1 source = src End Sub Public Function MoveNext() As Boolean index += 1 Return index < source.items.Length End Function Public ReadOnly Property Current As Integer Get Return source.items(index) End Get End Property End Class End Class Sub Main() For Each i As Integer In New CustomClass() Console.WriteLine(i) Next End Sub 'Output: '42 '666 '1234 '0 '-42
Cordialement !
C'est juste
Mais en pratique, je n'ai quasiment jamais vu de classe comme ça qui n'implémente pas IEnumerable. Même si implémenter l'interface ce n'est pas vraiment indispensable en soi, ça a l'avantage d'indiquer clairement que la classe supporte l'énumération. Et ça permet aussi l'utilisation avec Linq...
Pas de questions techniques par MP ! Le forum est là pour ça...
Tutoriels : Les nouveautés de C# 6 - Accès aux données avec Dapper - Extraction de données de pages web à l'aide de HTML Agility Pack - La sérialisation XML avec .NET (Aller plus loin) - Les markup extensions en WPF
On est bien d'accord, c'était plus dans un souci de précision.
D'ailleurs au passage on peut très bien utiliser Linq "à sa sauce" (ou pas) en réimplémentant les méthodes style SelectMany, Where... (avec les "bons prototypes pour ce que l'on veut) et pour faire d'autres choses (mais c'est une autre histoire ça) ; après dans la majorité des cas on veut le comportement de base donc là la question ne se pose même pas.
J'ai un peu exploré le sujet, en cherchant à détourner Linq pour d'autres utilisations monadiques.
Cordialement !
Pas de questions techniques par MP ! Le forum est là pour ça...
Tutoriels : Les nouveautés de C# 6 - Accès aux données avec Dapper - Extraction de données de pages web à l'aide de HTML Agility Pack - La sérialisation XML avec .NET (Aller plus loin) - Les markup extensions en WPF
Bonjour.
C'est effectivement ce que je veux faire. Je vais essayer ce que vous m'indiquez.
Merci beaucoup.
Bonjour.
tomlev a dit en substance
Soit. J'ai trouvé sur msdn un exemple de code. Je l'ai tant bien que mal adapté à mon cas :Pour faire du For Each, implémenter l'interface IEnumerable.
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 Public Class Bidasse Private _Nom As String Private _Prn As String Private _Sal As Double Public Property Nom As String Get Return _Nom End Get Set(ByVal nNom As String) _Nom = nNom End Set End Property Public Property Prénom As String Get Return _Prn End Get Set(ByVal nPrn As String) _Prn = nPrn End Set End Property Public Property Salaire As Double Get Return _Sal End Get Set(ByVal nSal As Double) _Sal = nSal End Set End Property End Class
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
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121 Imports System.Collections.Generic Public Class Adjudant Implements IEnumerable Private Col As System.Collections.Generic.List(Of Bidasse) Private _Nom As String Private _Prn As String Private _Sal As Double Public Sub New() Col = New System.Collections.Generic.List(Of Bidasse) End Sub Public Function Nombre() As Integer Return Col.Count End Function Default Public ReadOnly Property Item(ByVal Rng As Integer) As Bidasse Get Return Col.Item(Rng) End Get End Property Public Sub Ajouter(ByVal Infé As Bidasse) Col.Add(Infé) End Sub Public Sub Retirer(ByVal Rng As Integer) Col.RemoveAt(Rng) End Sub Public Sub Vider() Col.Clear() End Sub Public Function Rang(ByVal Infé As Bidasse) As Integer Dim i As Integer For i = 0 To Nombre() - 1 If Item(i) Is Infé Then Exit For Next i Return i End Function Public Property Nom As String Get Return _Nom End Get Set(ByVal nNom As String) _Nom = nNom End Set End Property Public Property Prénom As String Get Return _Prn End Get Set(ByVal nPrn As String) _Prn = nPrn End Set End Property Public Property Salaire As Double Get Return _Sal End Get Set(ByVal nSal As Double) _Sal = nSal End Set End Property Private Adj() As Bidasse Public Sub New(ByVal LstAdj() As Bidasse) Adj = New Bidasse(LstAdj.Length - 1) {} Dim i As Integer For i = 0 To LstAdj.Length - 1 Adj(i) = LstAdj(i) Next i End Sub Public Function GetEnumerator() As IEnumerator Implements IEnumerable.GetEnumerator Return New AdjudantEnum(Adj) End Function Public Class AdjudantEnum Implements IEnumerator Public Adj() As Bidasse Dim i As Integer = -1 Public Sub New(ByVal LstAdj() As Bidasse) Adj = LstAdj End Sub Public Function MoveNext() As Boolean Implements IEnumerator.MoveNext i = i + 1 Return (i < Adj.Length) End Function Public Sub Reset() Implements IEnumerator.Reset i = -1 End Sub Public ReadOnly Property Current() As Object Implements IEnumerator.Current Get Try Return Adj(i) Catch ex As IndexOutOfRangeException Throw New InvalidOperationException() End Try End Get End Property End Class End Classet cela ne fonctionne pas. Quelqu'un pourraît-il m'expliquer pourquoi, et comment y remédier ?
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 Public Class Accueil Public Adj As New Adjudant Private Sub bTst_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles bTst.Click ConstruireProgrammme() Afficher() End Sub Private Sub ConstruireProgrammme() Dim Bid As Bidasse Bid = New Bidasse : Adj.Ajouter(Bid) Bid = New Bidasse : Adj.Ajouter(Bid) Bid = New Bidasse : Adj.Ajouter(Bid) End Sub Private Sub Afficher() Dim Bid As New Bidasse For Each Bid In Adj MsgBox(Bid.Nom) Next End Sub End Class
D'avance merci.
Ca veut dire quoi "ne fonctionne pas" ? Il faudrait que tu sois plus précis...
En tous cas, plusieurs remarques :
- Il vaudrait mieux implementer IEnumerable(Of T) plutôt que IEnumerable tout court, ça permettrait d'indiquer le type des éléments
- Puisque tu as une List(Of Bidasse), qui implémente elle-même IEnumerable(Of Bidasse), tu peux te simplifier la vie : dans GetEnumerator, renvoie simplement Col.GetEnumerator(). Ça évite de taper toute l'implémentation de l'énumérateur.
- Conceptuellement, dire qu'un adjudant est une collection de bidasses, ça me parait pas terrible... Ce sont ses subordonnés, mais ils ne font pas "partie" de lui. Il vaudrait mieux que l'adjudant expose sa collection de bidasses via une propriété :
Et pour l'énumérer, tu fais comme ça :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4 Public Property Bidasses As IEnumerable(Of Bidasse) Return Col End Get End Property
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3 For Each Bid In Adj.Bidasses MsgBox(Bid.Nom) Next
Pas de questions techniques par MP ! Le forum est là pour ça...
Tutoriels : Les nouveautés de C# 6 - Accès aux données avec Dapper - Extraction de données de pages web à l'aide de HTML Agility Pack - La sérialisation XML avec .NET (Aller plus loin) - Les markup extensions en WPF
Merci pour votre réponse.
Au lancement du programme, une erreur apparaît à la ligne 103 de la classe Adjudant.
J'ai une question indigente. Comment sortir proprement de la discussion après l'envoi d'un message ?
ta classe est une classe de données
for each est utile sur les collections
il n'y a aucune raison d'implémenter IEnumerable sur une classe de données, ni de faire un for each dessus
tu pars sur une mauvaise piste à mon avis, bien que certains t'aient suivi ^^
si tu veux parcourir tous tes bidasses il te faut juste une instance de collection
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8 dim bidasses as new list(of bidasse) dim b1 as new bidasse bidasses.add(b1) for each b as bidasse in bidasses next
Bonjour.
J'ai fait ce que vous m'avez indiqué dans votre avant dernière intervention. Le résultat est exactement ce que je souhaitais.
Je considère donc que mon problème est résolu, grâce à vous.
Un grand merci.
Partager