For-each loop over eigen class. Bug in Excel v. Mac

Pagina: 1
Acties:

  • onkl
  • Registratie: Oktober 2002
  • Nu online
Hoi allen.

Ik ben bezig met een constructie waarvoor ik een class module gebruik om een collectie van objecten uit een andere class te beheren.
Relevante code:
Visual Basic:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
'Class planets
Option Explicit
Private mcolPlanets As New Collection
Public Function Add(strName As String) As Planet
    Dim PlanetNew As New Planet
PlanetNew.Name = strName
    mcolPlanets.Add PlanetNew, strName
    Set Add = PlanetNew
End Function

Public Function Item(strName As String) As Planet
    Set Item = mcolPlanets.Item(strName)
End Function

Public Function NewEnum() As IUnknown
    Set NewEnum = mcolPlanets.[_NewEnum]
End Function

(Planet is een andere Class, met de "beheerde" objecten)
(voor hen die zich hierin interesseren, dit komt nog uit deze tutorial, aanrader)

Stel dat je nu in je code een constructie als
Visual Basic:
1
2
3
For Each planetObject In starObject.Planets
'bla bla
Next planetObject

wilt gebruiken, dan zal je de NewEnum functie een Procedure ID van -4 meegeven (dan "weet" de for-next constructie dat dat de enumerator functie is).
In Excel-VBA kan je Procedure ID's niet normaal bewerken, maar wel via een hier omschreven trucje: exporteer de class en zet er in notepad de relevante teksten bij. Importeer en het werkt.
Tot zoverre (ik werk zelf op Excel 2002) geen probleem.

Echter, het geheel moet ook werken op Excel X for Mac.
En dat doet het niet... Het geeft dezelfde fouten die Excel v Windows gaf voordat ik de procedure ID's bewerkte.
Weet iemand misschien waar de mac-implementatie de fout ingaat en wat hiertegen te doen is? Google hielp me niet verder.

Verwijderd

he, vb developer workshop, een van de weinige developer boeken die ik me ooit heb aangeschaft, en nu zomaar beschikbaar op google books.
indien het niet mogelijk is de proceduredefaulteigenschap in te stellen in mac-excel - waarschijnlijk een onherstelbare onvolledige vba-implementatie van microsoft (bv. klassemodulemogelijkheid werd bij mac ook veel later toegevoegd), vrees ik dat er niets anders op zit de klasses te herontwerpen.
Je kan de enumeratie herstellen door de collection objecten publiek te maken - wat het overladen van de item en add methodes eigenlijk ook overbodig maakt - een volledig redesign van de klasses maw.
wat wel niet mogelijk zal zijn is object tree traversal. iets zoals Zon.Planets("Aarde").Moons("Maan").diameter zal in stappen moeten gebeuren.

  • onkl
  • Registratie: Oktober 2002
  • Nu online
Op zich kan je rustig door de object tree wandelen, alleen is Item niet de default eigenschap. Dat is wel te overzien:
Zon.Planets.item("Aarde").Moons.item("Maan").diameter werkt gewoon.
Alleen enumeratie is een beetje vervelend, vooral for-next achtig gebruik ontkom ik niet aan. Ik heb nu in de "Planets" en "Moons" klassen een eigen enumerator gebouwd (array met de objectnamen bijhouden en een simpele "getnext" routine). Werkt wel enigszins, al is het bepaald niet charmant. Gelukkig is het project zo klein dat resource-efficientie irrelevant is.

Misschien is het publiek maken van de collecties een optie, al overzie ik nog even niet wat de consequenties daarvan zijn. (one way to find out... :) )

Mac implementatie is inderdaad afschuwelijk bij tijd en wijle, maar ik ben al blij zat dat een huis-tuin-en-keuken prutser als ik tenminste een taal beheers die -tot op zekere hoogte- crossplatform werkt. Gelukkig had de opdrachtgever geen "Macding" over om zo af en toe een rondje te debuggen, dus zie ik voorlopig nog niet wat er allemaal fout gaat. 8)7

  • Lustucru
  • Registratie: Januari 2004
  • Niet online

Lustucru

26 03 2016

Inde tijd van voor For each X in Y moest je iets doen als:
code:
1
2
3
For i = 0 to Y.count
      set Z = Y(i)
Next i

Dat zou zelfs op een Mac nog moeten werken. Of was dat de vraag niet?

Niet dus. Maar je hoeft dus niet perse de hele collectie publiek te maken, alleen getitem(i) en Y.count

[ Voor 23% gewijzigd door Lustucru op 29-08-2007 19:57 ]

De oever waar we niet zijn noemen wij de overkant / Die wordt dan deze kant zodra we daar zijn aangeland


Verwijderd

ik denk dat dit wel compatibel zal zijn met de mac. als nadeel heeft het wel dat het niet sommige dingen (toevoegen bv.) netjes binnen een klasse afhandelt, maar goed.
maak drie klassen STER, PLANEET, MAAN:
Visual Basic:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
'klasse STER
Option Explicit

Public DIAMETER As Long
Public NAAM     As String
Public PLANETEN As Collection

Private Sub Class_Initialize()
  Set PLANETEN = New Collection
End Sub

Private Sub Class_Terminate()
  Set PLANETEN = Nothing
End Sub

Public Property Get Item(ByVal Sleutel As String) As PLANEET
  Set Item = PLANETEN(Sleutel)
End Property
Visual Basic:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
'klasse=PLANEET
Option Explicit

Public DIAMETER As Long
Public NAAM     As String
Public MANEN    As Collection

Private Sub Class_Initialize()
  Set MANEN = New Collection
End Sub

Private Sub Class_Terminate()
  Set MANEN = Nothing
End Sub

Public Property Get Item(ByVal Sleutel As String) As MAAN
  Set Item = MANEN(Sleutel)
End Property
Visual Basic:
1
2
3
4
5
'klasse=MAAN
Option Explicit

Public DIAMETER As Long
Public NAAM     As String
Visual Basic:
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
'module creeerzonnestel met mac-compatibele
'for each & object tree traversal:
Option Explicit

Sub OnsZonneStelsel_Bijnatoch()
  Dim JannekeMaan           As MAAN
  Dim EenPlaneet            As PLANEET
  Dim EenSterZoalsEenAnder  As STER
  
  Set EenSterZoalsEenAnder = New STER
  EenSterZoalsEenAnder.NAAM = "Zon"
  EenSterZoalsEenAnder.DIAMETER = 15000000
  Set EenPlaneet = New PLANEET
  EenPlaneet.NAAM = "Aarde"
  EenPlaneet.DIAMETER = 40000
  Set JannekeMaan = New MAAN
  JannekeMaan.NAAM = "Maan"
  JannekeMaan.DIAMETER = 8000
  EenPlaneet.MANEN.Add JannekeMaan, "Maan"
  Set JannekeMaan = Nothing
  EenSterZoalsEenAnder.PLANETEN.Add EenPlaneet, "Aarde"
  Set EenPlaneet = Nothing
  Set EenPlaneet = New PLANEET
  EenPlaneet.NAAM = "Mars"
  EenPlaneet.DIAMETER = 25000
  EenSterZoalsEenAnder.PLANETEN.Add EenPlaneet, "Mars"
  Set EenPlaneet = Nothing
  MsgBox _
      ( _
        "de " & EenSterZoalsEenAnder.NAAM & " heeft " & _
        EenSterZoalsEenAnder.PLANETEN.Count & " Planeten" _
      )
  For Each EenPlaneet In EenSterZoalsEenAnder.PLANETEN
    MsgBox _
        ( _
          "Planeet " & EenPlaneet.NAAM & _
          " heeft een diameter van " & _
          EenPlaneet.DIAMETER _
        )
    For Each JannekeMaan In EenPlaneet.MANEN
      MsgBox _
          ( _
            "planeet " & EenPlaneet.NAAM & _
            " heeft oa volgende maan :" & _
            JannekeMaan.NAAM _
          )
    Next
  Next
  MsgBox EenSterZoalsEenAnder.PLANETEN.Item("Mars").DIAMETER
  MsgBox EenSterZoalsEenAnder.PLANETEN.Item("Aarde").MANEN.Item("Maan").NAAM
  Set EenSterZoalsEenAnder = Nothing
End Sub


en g_d zei : "i can has light" :)
disclaimer:de diameter-getallen bevatten niet noodzakelijk hoog-educatieve waardes.

  • onkl
  • Registratie: Oktober 2002
  • Nu online
Leuk trucje.

Zoals gezegd, ik heb geen mac bij de hand. Zal het morgen even laten testen.
Dank iig.

  • onkl
  • Registratie: Oktober 2002
  • Nu online
Inderdaad. Het werkt perfect op de Mac. d:)b
Ik denk dat ik om de nadelen hiervan die je noemt wel kan heenwerken, dus die vormen geen beletsel.
Pagina: 1