In ambiente Visual Basic (VB6, VBA VB.Script ecc...) siamo abituati a trovare, negli oggetti che rappresentano un insieme di elementi come le
Collection delle
funzionalità standard : il supporto al costrutto
For Each ed una proprietà predefinita o default.
Prendiamo ad esempio un oggetto ADO come un recordset, in VB.Script (ad es. da ASP).
E' comune poter scorrere l'insieme
Fields dell'oggetto
Recordset in questo modo:
Set rs = CreateObject("ADODB.Recordset")
'... apre recordset
For Each f In rs.Fields
Response.Write f.Value
Next
'...chiude recordset
Anzichè utilizzare un ciclo
For...To come questo:
Set rs = CreateObject("ADODB.Recordset")
'... apre recordset
For i=0 to rs.Fields
Response.Write f.Value
Next
'...chiude recordset
Altrettanto comune è riferirsi ad una proprietà predefinita di un'oggetto come:
Response.Write rs (0)
Anzinchè
rs.Fields.Item (0)
Quando creiamo un oggetto in .NET che intendiamo utilizzare da COM ci sono degli accorgimenti da adottare per mettere a disposizione
queste funzionalità.
Ometto naturalmente di parlare di come esporre un oggetto .NET a COM (ulteriori spiegazioni le potete trovare nell'articolo
How to call a Visual Basic .NET assembly from Visual Basic 6.0
and how to call a call Visual Basic COM component from Visual Basic .NET di Microsoft).
Partiamo quindi dal presupposto che avete creato una classe .net da esporre a COM come
Collection.
Una classe semplicissima che contiene:
- una lista ArrayList privata
- un metodo pubblico Add per aggiungere un oggetto
- una proprietà Item per ottenere un oggetto dalla lista utilizzando un indice
Questo è il codice :
<Guid("56A66686-22D8-4eab-8F02-9758A21F6EFB"), ClassInterface(ClassInterfaceType.AutoDual)> _
Public Class MyCollection
Private _list As ArrayList
Public ReadOnly Property list() As ArrayList
Get
If _list Is Nothing Then
_list = New ArrayList
End If
Return _list
End Get
End Property
Public Function Add(ByVal obj As Object) As Integer
Return list.Add(obj)
End Function
Public ReadOnly Property Item(ByVal index As Integer) As Object
Get
Return list(index)
End Get
End Property
End Class
Per abilitare la funzionalità
For...Each dai client VB.Script occorre implementare
l'interfaccia
IEnumerable ed il metodo
GetEnumerator() mentre
per definire la proprietà di default si deve aggiungere l'attributo
DispId(0).
Io l'ho fatto così:
<Guid("56A66686-22D8-4eab-8F02-9758A21F6EFB"), ClassInterface(ClassInterfaceType.AutoDual)> _
Public Class MyCollection
Implements IEnumerable '<--implementa IEnumerable
Private _list As ArrayList
Public ReadOnly Property list() As ArrayList
Get
If _list Is Nothing Then
_list = New ArrayList
End If
Return _list
End Get
End Property
Public Function Add(ByVal obj As Object) As Integer
Return list.Add(obj)
End Function
<DispId(0)> _ '<--Trasforma Item nella Default Property
Public ReadOnly Property Item(ByVal index As Integer) As Object
Get
Return list(index)
End Get
End Property
'implementa GetEnumerator
Public Function GetEnumerator() As System.Collections.IEnumerator Implements System.Collections.IEnumerable.GetEnumerator
Return Me.list.GetEnumerator
End Function
End Class
Nota: è possibile omettere l'implementazione di IEnumerable quando si eredita la classe da un'oggetto
Collection di .NET come ArrayList, HashTable ecc... perchè questi oggetti a loro volta implementano IEnumerable.
In questo modo il client VB.Script potrà utilizzare l'oggetto nel modo consueto:
set myColl = CreateObject("MyNamespace.MyCollection")
myColl.Add("Prova")
For Each s In myColl
Response.Write s
Next
'oppure anche
Response.Write myColl(0)