Newsgroup: it.comp.lang.visual-basic
Titolo: VB.Net - costruttori, istanze e structure

Supponete di avere una struttura e una classe:
Public Structure myStructure
     Public Name as String
     Public CAP as Integer
' ..ecc
End Structure
Public  Class myClass
    Private List() as myStructure ' semplice struttura di dati
    Public Count as Integer
    Public Sub PopulateRandom()
           ' carica n elementi random in list
    End Sub
    Public Function Clone() As myClass
              Dim e as New MyClass()
              For i = 1 to Count
                    e.Add(List(i))
              Next
              Return e
    End Function
    Public Sub Add(byVal obj as myStructure)
               Count= +1
               Redim Preserve List(Count)
               List(Count)=obj
    End Sub
End Class
Nell'applicazione:
Dim c1 as New MyClass()
Dim c2 as New MyClass()
c1.PopulateRandom ' ipotetico metodo che carichi l'array List() di c1
c2=c1.Clone   '<---- qui il Clone dovrebbe crearmi un duplicato esatto di
c1, come nuova istanza di myClass
in realtà, ogni modifica a List in c2, la trovo riflessa nella List di c1..
sembra che c2 sia il riferimento di c1, mentre l'ho creata nuova.
la cosa strana, nella mia applicazione, è che oltre a List ci sono altre
proprietà che le vedo come distinte.. solo l'array List sembra condivisa.
Non vorrei che dipendesse dalla dichiarazione della struttura dati..
Fabio Guerrazzi

 sembra che c2 sia il riferimento di c1, mentre l'ho creata nuova.
Da te proprio questa non me l'aspettavo :)
Guarda bene: la Clone() crea una copia con tutti i *riferimenti* agli
oggetti della lista.
Quello che ti serve è il CopyTo().
Ciao
--
Math Parser : 
http://www.neodatatype.net
Sito Comune : 
http://www.it-lang-vb.net

 Quello che ti serve è il CopyTo().
hmm.. vado a vedere che dice e provo..

 hmm.. vado a vedere che dice e provo..
fa uguale :(

Fabio,
Il tuo codice ha un po di errori...
1-MyClass e' una keyword di 
VB.NET
 (stai usando Option Strict On?)
2-Count= +1 (???) semmai Count+=1
Comunque sia questo sembra funzionare le due copie sono indipendenti
Public Structure myStructure
    Public Name As String
    Public CAP As Integer
End Structure
Public Class myClass2
    Private List() As myStructure ' semplice struttura di dati
    Public Count As Integer
    Public Sub PopulateRandom()
        Dim ms As myStructure
        ms.Name = "n1"
        ms.CAP = 1234
        Me.Add(ms)
        Dim ms2 As myStructure
        ms.Name = "n2"
        ms.CAP = 5678
        Me.Add(ms2)
    End Sub
    Public Function Clone() As myClass2
        Dim e As New myClass2
        For i As Int32 = 1 To Count
            e.Add(List(i))
        Next
        Return e
    End Function
    Public Sub Add(ByVal obj As myStructure)
        Count += 1
        ReDim Preserve List(Count)
        List(Count) = obj
    End Sub
End Class
  Dim c1 As New myClass2
        c1.PopulateRandom()
        Dim c2 As myClass2 = c1.Clone()
        Dim ms As myStructure
        ms.Name = "pippo"
        ms.CAP = 9876
        c1.Add(ms)
        Dim i As Int32 = c2.Count
HTH
-- 
Corrado Cavalli [Microsoft .NET MVP-MCP]
UGIdotNET - 
http://www.ugidotnet.org
Weblog: 
http://www.ugidotnet.org/710.blog

Dimenticavo: Puoi fare una shallow copy di un oggetto semplicemente usando
MemberWiseClone()



se passi ByVal una istanza di un reference type, ottieni la creazione di una
copia della reference, non dell'oggetto.
-- 
.A
UGIdotNET - User Group Italiano .NET
http://www.ugidotnet.org
Read my blog at: 
http://www.ugidotnet.org/4.blog

 Fabio Guerrazzi


         Dim i As Int32 = c2.Count
Scusa, puoi provare anche questo, visto che hai il test:
c2.UpdateCAP(1,99999)
Sub UpdateCAP(ByVal Index As Integer, ByVal value As Integer)
       list(index).CAP=Value
End Sub
Grazie

 copia della reference, non dell'oggetto.
spiega meglio
io sapevo che ByVal crea una nuova locazione di memoria per la variabile,
copiandoci il contenuto dell'originale, mentre il ByRef passa il puntatore
condividendo l'area


grazie, ne terrò conto

[*Fabio Guerrazzi* = 
fabio.guer...@virgilio.it
 in
news:AZ5Tb.174998$
VW.71...@news3.tin.it
] ha scritto:

Credo che stiate dicendo la stessa cosa.
ByVal "duplica" la variabile in un zona nuova di memoria, separata e
diversa.
Ogni sua variazione NON viene quindi riportata sull'originale che č rimasta
dov'č e com'č.
ByRef "lavora" direttamente sulla variabile originale, non ne viene fatta
una copia, quindi le variazioni sono sulla stessa.

Infatti stai passando una copia di un riferimento, quindi, avendo due
riferimenti uguali, stai alla fine puntando allo stesso oggetto.


 Scusa, puoi provare anche questo, visto che hai il test:
Il codice l'ho comunque postato interamente..., la risposta č: Tutto Ok, hai
due copie distinte (provare per credere)



Siamo d'accordo sulla differenza tra riferimento e oggetto.
Quello che non riesco a capire, qui, dov'è il riferimento...
List(i) è l'oggetto nudo e crudo
Ovvio che sbaglio qualcosa, e che in qualche posto passa i rifirementi
invece dell'oggetto,  ma non mi è chiaro dove.
        Public Function Clone() As Entities
            Dim i As Integer
            Dim e As New Entities()
            Dim c As EntityRecord
            ' ReDim c(Count)
            ' List.CopyTo(c, 0)
            For i = 1 To Count
                c = List(i)
                e.Pen = c.Pen
                e.Add(c)
                e.Pen = Nothing



urka! Il discorso non è breve... Provo a sintetizzare (anche se ti consiglio
di studiare _seriamente_ il binomio CLR+framework prima di intraprendere lo
sviluppo per .NET)... Il type-system di .NET è "single-rooted", ossia tutti
i tipi (anche integer, per intenderci) derivano (ossia ereditano) il tipo
object. Ciò nonostante, esistono due famiglie "logiche" di tipi, che si
differenziano per il modo nel quale il runtime (il CLR, per intenderci)
gestisce le loro istanza in memoria. La prima famiglia è qlla dei reference
type (come String, per intenderci). Qndi tu scrivi:
Dim s as String = "CIAO"
in realtà il CLR alloca nello heap uno spazio sufficiente a contenere
l'effettiva istanza (l'oggetto, per intenderci), e piazza sullo stack un
riferimento (un puntatore, per intenderci) alla istanza. Quando tu usi il
riferimento ("s", nel succitato caso), il CLR recupera dallo stack il
puntatore effettivo, e va a "prendere" l'oggetto nello heap. Ci sono poche
cose certe nella vita, ma una di esse è che una istanza di reference type
vivrà _sempre_ nello heap.
La seconda famiglia è qlla dei value type (interi, enumerativi, strutture,
...) che tipicamente occupano poca memoria, e dei quali è preponderante
l'uso dello stato (i dati, per intenderci) piuttosto che della logica
interna. Per evitare penalizzazioni nelle performance di calcolo, le istanze
di value type sono _tipicamente_ allocate nello stack, e il CLR ha accesso
diretto ai valori contenuti. In pratica, qndo esegui somme tra interi, non
stai frugando nello heap ma lavori direttamente sullo stack: ecco perchè le
performance di .NET sono elevate anche in qsto caso (_sicuramente_ maggiori
a qlle di VB6, per intenderci). Perchè ho detto "tipicamente allocate nello
stack"? Perchè esiste una tecnica, nota come "boxing", che viene attuata dal
CLR quando tenti di usare una istanza di value type come oggetto (è una
definizione volutamente approssimativa, ma per il momento va bene così). In
pratica, qndo tu scrivi:
Dim i As Integer =4
Dim o As Object = i
il CLR "boxa i in o", ossia alloca temporaneamente nello heap risorse
sufficienti a contenere l'istanza di integer, copia il contenuto di "i" in
questa area, e piazza sullo stack un riferimento ad essa, chiamandolo "o".
In ogni momento, potrai ritornare ad utilizzare come numero il valore
contenuto in "o" effettuando un  cast di "o" da object ad integer, che
causerà una operazione di "unboxing". Ora, tornando alla tua domanda, quando
tu passi come "ByVal" un argomento, devi distinguere due casi:
1) Il tipo dell'argomento è un value type: il runtime crea come variabile
automatica una copia del valore passato. La variabile originale e la copia
sottointendono differenti zone di memoria, e sono utilizzabili
indipendentemente
2) Il tipo dell'argomento è un reference type: il runtime crea "solo" una
copia della reference, ma sia la reference originale sia la copia
sottointendono la stessa zona di memoria, ossia "puntano" lo stesso oggetto.
Questa scelta di design è sensata poichè altrimenti passare (ad esempio) un
dataset per valore avrebbe causato una clonazione implicita, il che non è
bello (se non avviene esplicitamente) da un punto di vista delle
performance.
Qui:
http://www.ugidotnet.org/workshops/workshops_read.aspx?WorkshopID=1
trovi il materiale della sessione "Da VB a VB .NET" nel quale troverai
qualche ulteriore approfondimento.
ciao,
-- 
.A    [Microsoft MVP .NET]



sono un pollo: ho dimenticato di linkarti anche qsto:
http://www.yoda.arachsys.com/csharp/memory.html
(è in C#, ma nel "mondo .NET" il linguaggio è un dettaglio...)
ri-ciao,


"Andrea Saltarello"
[snip&saved]
ti amo.
ma non riesco a capire, comunque, come posso clonare la mia classe Entities,
copiando *fisicamente* anche l'intera array "List"
questa č la mia clone:
ps. MemberWiseClone mi da lo stesso risultato.
       Public Function Clone() As Entities
            Dim i As Integer
            Dim e As New Entities()
            Dim c As EntityRecord
            For i = 1 To Count
                c = List(i)
                e.Pen = c.Pen
                e.Add(c)
                e.Pen = Nothing
            Next
            Return e
        End Function
dovrei forse assegnare *c* campo per campo
 c.campo1=List(i).campo1
ecc..
prima di passarlo ad Add() ?

 sottointendono la stessa zona di memoria, ossia "puntano" lo stesso
oggetto.
Che è quello che succede anche con VB6, cioè passando un oggetto byval in
realtà si passa solo la copia del puntatore e quindi si lavora comunque
sull'oggetto originale.


 lavora comunque sull'oggetto originale.
Prego?

"Andrea Saltarello"
risolto.
ho dovuto copiare campo per campo la struttura.
cosě funziona.
perň ancora non mi torna che non si possa *copiare* e passare a un'altra
istanza i dati riferiti a un oggetto fisico.
se ho un oggetto A, a cui faccio riferimento con B, dovrei, in qualche modo
poter creare un duplicato di A accedendoci con B.
-- 
Fabio Guerrazzi

Qualche concetto base...
http://www.codeproject.com/dotnet/Clone.asp
Puoi ottenere una deep copy serializzando e deserializzando l'oggetto
http://www.devx.com/vb2themax/Tip/18708


 
http://www.devx.com/vb2themax/Tip/18708
ah ecco, mi pareva.
qualche metodo empirico doveva esistere
Grazie


credo che stesse parlando di tipi di dati definiti dall'utente.
in vb6 non puoi passarli da una classe all'altra come parametro.
in dotNet, con grande sorpresa si, ma non avevo tenuto conto di queste
considerazioni

 Prego?
non si è sbagliato, intendeva proprio ciò che hai letto.
In vb6 una variabile oggetto rappresenta semplicemente un riferimento
all'area di memoria allocata dall'oggetto (una sorta di puntatore).
Quando lo istanzi, l'oggetto viene allocato nello heap, il reference
count viene incrementato e l'indirizzo di memoria dell'oggetto viene
copiato nella tua variabile.
Quando con un'altra variabile oggetto imposti un riferimento alla
stessa istanza, il reference count viene nuovamente incrementato e
l'indirizzo viene copiato anche nella seconda variabile.
Ora se passi ad una funzione questa tua istanza per valore, non gli
passi una copia dell'oggetto, bensì una copia del suo riferimento:
anche qui il reference count viene incrementato. La funzione quindi
accederà sempre alla stessa istanza dell'oggetto, ma utilizzando un
riferimento diverso: potrà modificare le sue proprietà, ma non potrà,
ad esempio, distruggerlo. Al termine della funzione, cessa lo scope
del parametro ed il reference count viene diminuito. Se la passi
byref, invece, gli passi il riferimento al riferimento, quindi
permetti alla funzione di accedere direttamente al contenuto della tua
variabile.
In parole povere e andando direttamente al pratico (una possibile
implicazione), se sei abituato a rilasciare le risorse allocate al
termine di ogni funzione e settare tutti gli oggetti a nothing, occhio
a passarli byref...
Di solito si preferisce passare gli oggetti byref all'interno del
proprio processo, per ragioni di performance, mentre è preferibile
passarli byval a componenti out-of-process, per evititare che il
marshaler debba faticare due volte per "marshalare" l'oggetto (come si
dice in italiano?) sia in ingresso che in uscita...
HTH,
Moreno

 non si è sbagliato, intendeva proprio ciò che hai letto.
Sì, mi scuso.
Avevo fatto una prova che non riesco più a riprodurre.
Suppongo, per errore, che passavo il valore di una proprietà dell'oggetto e
non l'oggetto stesso.