Il blog di Gianni Giaccaglini

Blog su VBA e VSTO
Gianni Giaccaglini

My Links

News

NB - V. anche gli ARTICOLI (in fondo a questa barra)
Solo quesiti validi a: giannigiac@tin.it
Il mio nuovo libro


La mia nipotina ELISA

Foto con dedica a ME di
Bill Gates giovanissimo
nei mitici anni 80!

Categorie Post

Categorie Articoli

Archivio

Immagini

Blog Stats

Un'ambiguità semantica (apparente) del ciclo For Each

Ambiguità sematica del ciclo For Each?

Anche questa è una divagazione di mezza estate. Riporto quasi pari pari il carteggio fra me e Francesco Balena.

Una cosuccia strana non scritta da nessuna parte. Il ciclo For Each... Next si direbbe che funzioni solo IN LETTURA, come nello snippet seguente:

Sub Main()

  Dim MiaLista As New List(Of Integer)

  Dim V() As Integer = {1, 2, 3, 4, 5}

  For i = 0 To UBound(V)

    MiaLista.Add(V(i))

  Next

  For Each el As Integer In MiaLista

    el *= 2 ' Accolta “sulla carta”, ma senza REALI conseguenze

  Next

  For Each el As Integer In MiaLista

    Console.WriteLine(el) ' Continua a indicare 1, 2, 3, 4, 5

  Next

  Console.WriteLine()

  ' Solo con gl’indici le cose vanno bene:

  For i = 0 To MiaLista.Count - 1

    MiaLista(i) *= 2

  Next

  For Each el As Integer In MiaLista

    Console.WriteLine(el) ' Indica 2, 4, 6, 8, 10

  Next

  Console.ReadLine()

End Sub

 

La stessa delusione di aspettative (ingenue?) si ha con le matrici, del tipo Dim (V).

Qualcuno avrà l’onestà di ammettere che non lo sapeva? Forse e, magari, i più esperti (per lo più dimentichi di segnalare la cosa all’inclita e al volgo) forniranno dotte delucidazioni.

Ma attenzione! Non è finita. Infatti con le Liste (e simili) di OGGETTI le cose funzionano come ci si attende:

Module Module1

  Class Persona

    Public Nome As String

  End Class

 

  Sub Main()

    Dim VettNomiPers() = {"Ciccio", "Maria", "Luigi", "Paola"}

    Dim Persone As New List(Of Persona)

    Dim i As Integer = 0

    Dim UnaPersona As New Persona

    ' Carica VettNomiPers nella lista Persone

    For Each NomePers As String In VettNomiPers

      UnaPersona.Nome = NomePers

      Persone.Add(UnaPersona)

      UnaPersona = New Persona

    Next

    For Each UnaPersona In Persone

      Console.WriteLine(UnaPersona.Nome) ' => "Ciccio", "Maria" ecc.

      UnaPersona.Nome = "Ciao" ' => "Ciao"

      Console.WriteLine(UnaPersona.Nome)

    Next

    Console.WriteLine()

    Console.WriteLine("LISTA MODIFICATA:")

    For Each UnaPersona In Persone

    Console.WriteLine(Persone(i).Nome) ' => Tutti Ciao

    Next

    Console.ReadLine()

  End Sub

End Module

 

NOTA – Funzionamento OK anche con ciclo finale indicizzato (ovvio) e con modifiche apportate a un eventuale campo numerico.

Come utenteilmente segnalerei la presenza di un problema semantico, con l’aggravante della contraddizione indicata nell’ultimo esempietto.

Do not forget, anyway.

LA (GIUSTA) REPLICA DI FRANCESCO BALENA:

Mi dispiace deluderti, ma questa feature è ben documentata. Basta andare a leggere il manuale ufficiale del linguaggio:

http://msdn.microsoft.com/en-us/library/5ebk1751.aspx

Modifying Collection Elements. The Current property of the enumerator object is ReadOnly (Visual Basic), and it returns a local copy of each collection element. This means that you cannot modify the elements themselves in a For Each...Next loop. Any modification you make affects only the local copy from Current and is not reflected back into the underlying collection. However, if an element is a reference type, you can modify the members of the instance to which it points. The following example illustrates this.

Il fatto che “sembri” funzionare con gli oggetti è una pura illusione, derivante probabilmente da un equivoco abbastanza comune tra i programmatori. Nel tuo esempio tu non modifichi la variabile “el” ma modifichi l’N-esimo elemento della lista a cui “el” punta. Non è un dettaglio da poco, anzi fa tutta la differenza.

Volendo fare una analogia, “el” è l’indirizzo fisico di un negozio con vetrina e ingresso, che oggi contiene un fruttivendolo. “el” è a sola lettura e infatti il numero civico di quella vetrina non cambierà mai, ma il contenuto di quel negozio può liberamente cambiare ed ospitare ad esempio una farmacia. Non a caso, si dice che una variabile “punta” a qualcosa, non che “contiene” qualcosa.

[ Per la cronaca, resta il fatto che in quasi nessun altro posto ho trovato queste precisazioni, comunque da NON obliare, anzi il più delle volte si lascia credere che For Each e For i = 0 To siano equivalenti... Beh dipende... ]

?>

posted on sabato 8 agosto 2009 11.41