dcsimg
Results 1 to 16 of 16

Thread: [RESOLVED] Is it possible to add an enumerator to an array?

  1. #1

    Thread Starter
    Frenzied Member
    Join Date
    Sep 2012
    Posts
    1,838

    Resolved [RESOLVED] Is it possible to add an enumerator to an array?

    I wonder if there is a way to add an enumerator to a VB array, for example:

    Code:
    For Each vArrayItem In vArray
        'Do something
    Next
    Class1
    Code:
    Option Explicit
    
    Private mItems() As Variant
    
    Public Property Get Item(ByVal Index As Long) As Variant
        Item = mItems(Index)
    End Property
    
    Public Property Let Item(ByVal Index As Long, NewVal As Variant)
        mItems(Index) = NewVal
    End Property
    
    Public Function NewEnum() As IUnknown
      Set NewEnum = mItems.[_NewEnum]
    End Function
    
    Private Sub Class_Initialize()
        mItems = Array(10)
    End Sub
    Thanks.

  2. #2
    PowerPoster Zvoni's Avatar
    Join Date
    Sep 2012
    Location
    To the moon and then left
    Posts
    2,087

    Re: Is it possible to add an enumerator to an array?

    IIRC, it is possible, but as a Property Get not a Function
    I think it was something like this:
    Tools|Procedure Attributes then click Advanced
    Select NewEnum
    Set Procedure ID to -4
    One System to rule them all, One IDE to find them,
    One Code to bring them all, and to the Framework bind them,
    in the Land of Redmond, where the Windows lie
    ---------------------------------------------------------------------------------
    People call me crazy because i'm jumping out of perfectly fine airplanes.
    ---------------------------------------------------------------------------------
    For health reasons i try to avoid reading unformatted Code

  3. #3

    Thread Starter
    Frenzied Member
    Join Date
    Sep 2012
    Posts
    1,838

    Re: Is it possible to add an enumerator to an array?

    Hi Zvoni, I tried your method and it still doesn't seem to work. The system prompts "Object required"

  4. #4
    PowerPoster Arnoutdv's Avatar
    Join Date
    Oct 2013
    Posts
    3,681

    Re: Is it possible to add an enumerator to an array?

    It only works for collections isn't it? Doesn't work for arrays in the class.

  5. #5
    PowerPoster Zvoni's Avatar
    Join Date
    Sep 2012
    Location
    To the moon and then left
    Posts
    2,087

    Re: Is it possible to add an enumerator to an array?

    Quote Originally Posted by Arnoutdv View Post
    It only works for collections isn't it? Doesn't work for arrays in the class.
    IIRC, it works for your own "Collection"-Classes, too (independent if internally it's a collection or an array)
    I remember doing something like that some 15 years ago, but i don't have the source-code anymore (at least i haven't seen it in 15 years).
    Bruce McKinney had an example in his HVB-Book

    EDIT: Found Bruce's Source-Code from HVB
    Code:
    Public Function NewEnum() As IEnumVARIANT
    Attribute NewEnum.VB_UserMemId = -4
    Last edited by Zvoni; Feb 14th, 2020 at 07:18 AM.
    One System to rule them all, One IDE to find them,
    One Code to bring them all, and to the Framework bind them,
    in the Land of Redmond, where the Windows lie
    ---------------------------------------------------------------------------------
    People call me crazy because i'm jumping out of perfectly fine airplanes.
    ---------------------------------------------------------------------------------
    For health reasons i try to avoid reading unformatted Code

  6. #6
    PowerPoster Arnoutdv's Avatar
    Join Date
    Oct 2013
    Posts
    3,681

    Re: Is it possible to add an enumerator to an array?

    I know it works for looping thru an array.
    I never saw a sample for the NewEnum on a variant array in a class.

    Did some searching, maybe this can be used as a skeleton:
    http://www.mvps.org/vbvision/Super_Collections.htm

  7. #7
    PowerPoster Zvoni's Avatar
    Join Date
    Sep 2012
    Location
    To the moon and then left
    Posts
    2,087

    Re: Is it possible to add an enumerator to an array?

    Arnout,

    yeah, kind looks familiar with the mentioned hacks
    One System to rule them all, One IDE to find them,
    One Code to bring them all, and to the Framework bind them,
    in the Land of Redmond, where the Windows lie
    ---------------------------------------------------------------------------------
    People call me crazy because i'm jumping out of perfectly fine airplanes.
    ---------------------------------------------------------------------------------
    For health reasons i try to avoid reading unformatted Code

  8. #8

    Thread Starter
    Frenzied Member
    Join Date
    Sep 2012
    Posts
    1,838

    Re: Is it possible to add an enumerator to an array?

    Quote Originally Posted by Arnoutdv View Post
    I know it works for looping thru an array.
    I never saw a sample for the NewEnum on a variant array in a class.

    Did some searching, maybe this can be used as a skeleton:
    http://www.mvps.org/vbvision/Super_Collections.htm
    Hi Arnoutdv, I downloaded and read the code from the link you provided, it's too complicated, I decided to give up adding an enumerator to the VB array. Thank you, Arnoutdv. Thank Zvoni too.

  9. #9
    PowerPoster
    Join Date
    Jun 2013
    Posts
    4,574

    Re: Is it possible to add an enumerator to an array?

    Quote Originally Posted by dreammanor View Post
    I decided to give up adding an enumerator to the VB array.
    One easy way is, to return the "Array itself" via an Items-Property (since VB can enumerate on its own SafeArrays).

    Class1-Code:
    Code:
    Option Explicit
     
    Private mItems() As Variant
     
    Private Sub Class_Initialize()
      mItems = Array() 'inits the array (though still with no members)
    End Sub
    
    Public Sub push(Item)
      ReDim Preserve mItems(0 To UBound(mItems) + 1): mItems(UBound(mItems)) = Item
    End Sub
    Public Property Get length() As Long
      length = UBound(mItems) + 1
    End Property
    
    Public Property Get Item(ByVal Index As Long) As Variant '<- usually with Default-Attribute set
      Item = mItems(Index)
    End Property
    Public Property Let Item(ByVal Index As Long, RHS As Variant)
      mItems(Index) = RHS
    End Property
    
    Public Property Get Items() As Variant()
      Items = mItems
    End Property
    And Test-Form-Code:
    Code:
    Private Sub Form_Load()
      Dim Arr As New Class1, V
          Arr.push 1
          Arr.push 2
          Arr.push 3
      
      Debug.Print "Arr-length: "; Arr.length
      
      For Each V In Arr.Items '<- but Items needs to be specified explicitely then
        Debug.Print V
      Next
    End Sub

    Another variant for "easy enumerations" would be, to use an RC5-Helper for that,
    (in conjunction with "flagging" the Enumerator-method of the Class with AttributeID= -4)
    Class1-Code:
    Code:
    Option Explicit
    
    Implements IEnumerable 'we implement the IEnumerable-Interface from RC5
    
    Private mItems() As Variant
    
    Private Sub Class_Initialize()
      mItems = Array() 'inits the array (though still with no members)
    End Sub
    
    Public Sub push(Item)
      ReDim Preserve mItems(0 To UBound(mItems) + 1): mItems(UBound(mItems)) = Item
    End Sub
    Public Property Get length() As Long
      length = UBound(mItems) + 1
    End Property
    
    Public Property Get Item(ByVal Index As Long) As Variant '<- usually with Default-Attribute set
      Item = mItems(Index)
    End Property
    Public Property Let Item(ByVal Index As Long, RHS As Variant)
      mItems(Index) = RHS
    End Property
    
    Public Property Get Items() As Variant()
      Items = mItems
    End Property
    
    Public Function NewEnum() As IUnknown '<- needs Enumerable-ProcAttribute: -4
      Set NewEnum = New_c.EnumerateOn(Me, UBound(mItems) + 1)
    End Function
    Private Function IEnumerable_NextItem(Idx As Long) As Variant 'this is the IEnumerable-Callback
      IEnumerable_NextItem = mItems(Idx)
    End Function
    And Test-Form-Code again:
    Code:
    Private Sub Form_Load()
      Dim Arr As New Class1, V
          Arr.push 1
          Arr.push 2
          Arr.push 3
      
      Debug.Print "Arr-length: "; Arr.length
      
      For Each V In Arr.Items '<- but Items needs to be specified explicitely then
        Debug.Print V
      Next
      
      For Each V In Arr '<- now one can also directly enumerate on Arr
        Debug.Print V
      Next
    End Sub
    HTH

    Olaf

  10. #10
    Frenzied Member wqweto's Avatar
    Join Date
    May 2011
    Posts
    1,720

    Re: [RESOLVED] Is it possible to add an enumerator to an array?

    http://www.vbforums.com/showthread.p...hout-a-typelib

    Here is a "raw" implementation of a handy IEnumVARIANT light-weight object. It just forwards IEnumVARIANT::Next to parent object's default method with some code like this

    VariantCopyToPtr rgVar, .Enumerable(.Index)

    . . . so this trades the need to implement a custom IEnumerable interface for a bit of speed.

    Of course RC5's solution is probably a lot more stable in the IDE as first it's a compiled DLL and second it's been excercised a bit more in the wild for some years now.

    cheers,
    </wqw>

  11. #11

    Thread Starter
    Frenzied Member
    Join Date
    Sep 2012
    Posts
    1,838

    Re: Is it possible to add an enumerator to an array?

    Quote Originally Posted by Schmidt View Post
    One easy way is, to return the "Array itself" via an Items-Property (since VB can enumerate on its own SafeArrays).

    Class1-Code:
    Code:
    Option Explicit
     
    Private mItems() As Variant
     
    Private Sub Class_Initialize()
      mItems = Array() 'inits the array (though still with no members)
    End Sub
    
    Public Sub push(Item)
      ReDim Preserve mItems(0 To UBound(mItems) + 1): mItems(UBound(mItems)) = Item
    End Sub
    Public Property Get length() As Long
      length = UBound(mItems) + 1
    End Property
    
    Public Property Get Item(ByVal Index As Long) As Variant '<- usually with Default-Attribute set
      Item = mItems(Index)
    End Property
    Public Property Let Item(ByVal Index As Long, RHS As Variant)
      mItems(Index) = RHS
    End Property
    
    Public Property Get Items() As Variant()
      Items = mItems
    End Property
    And Test-Form-Code:
    Code:
    Private Sub Form_Load()
      Dim Arr As New Class1, V
          Arr.push 1
          Arr.push 2
          Arr.push 3
      
      Debug.Print "Arr-length: "; Arr.length
      
      For Each V In Arr.Items '<- but Items needs to be specified explicitely then
        Debug.Print V
      Next
    End Sub

    Another variant for "easy enumerations" would be, to use an RC5-Helper for that,
    (in conjunction with "flagging" the Enumerator-method of the Class with AttributeID= -4)
    Class1-Code:
    Code:
    Option Explicit
    
    Implements IEnumerable 'we implement the IEnumerable-Interface from RC5
    
    Private mItems() As Variant
    
    Private Sub Class_Initialize()
      mItems = Array() 'inits the array (though still with no members)
    End Sub
    
    Public Sub push(Item)
      ReDim Preserve mItems(0 To UBound(mItems) + 1): mItems(UBound(mItems)) = Item
    End Sub
    Public Property Get length() As Long
      length = UBound(mItems) + 1
    End Property
    
    Public Property Get Item(ByVal Index As Long) As Variant '<- usually with Default-Attribute set
      Item = mItems(Index)
    End Property
    Public Property Let Item(ByVal Index As Long, RHS As Variant)
      mItems(Index) = RHS
    End Property
    
    Public Property Get Items() As Variant()
      Items = mItems
    End Property
    
    Public Function NewEnum() As IUnknown '<- needs Enumerable-ProcAttribute: -4
      Set NewEnum = New_c.EnumerateOn(Me, UBound(mItems) + 1)
    End Function
    Private Function IEnumerable_NextItem(Idx As Long) As Variant 'this is the IEnumerable-Callback
      IEnumerable_NextItem = mItems(Idx)
    End Function
    And Test-Form-Code again:
    Code:
    Private Sub Form_Load()
      Dim Arr As New Class1, V
          Arr.push 1
          Arr.push 2
          Arr.push 3
      
      Debug.Print "Arr-length: "; Arr.length
      
      For Each V In Arr.Items '<- but Items needs to be specified explicitely then
        Debug.Print V
      Next
      
      For Each V In Arr '<- now one can also directly enumerate on Arr
        Debug.Print V
      Next
    End Sub
    HTH

    Olaf
    The above two solutions are exactly what I need, especially the second solution using RC5.IEnumerable, which is perfect. Olaf, you are like a magician, you can always pull something amazing out of your hat. Much appreciated!

  12. #12

    Thread Starter
    Frenzied Member
    Join Date
    Sep 2012
    Posts
    1,838

    Re: [RESOLVED] Is it possible to add an enumerator to an array?

    Quote Originally Posted by wqweto View Post
    http://www.vbforums.com/showthread.p...hout-a-typelib

    Here is a "raw" implementation of a handy IEnumVARIANT light-weight object. It just forwards IEnumVARIANT::Next to parent object's default method with some code like this

    VariantCopyToPtr rgVar, .Enumerable(.Index)

    . . . so this trades the need to implement a custom IEnumerable interface for a bit of speed.

    Of course RC5's solution is probably a lot more stable in the IDE as first it's a compiled DLL and second it's been excercised a bit more in the wild for some years now.

    cheers,
    </wqw>
    Hi wqweto, the information you provided is very useful. At present, I'll use Olaf's method, and the DEXWERX's solution will be put into my database for future learning materials. Thank you very much, wqweto.

  13. #13
    Frenzied Member wqweto's Avatar
    Join Date
    May 2011
    Posts
    1,720

    Re: [RESOLVED] Is it possible to add an enumerator to an array?

    @Olaf: Just fiddled a bit with the RC5 enumerator impl and found that the following line brings the IDE down

    Debug.Print TypeName(Arr.NewEnum)

    While you at it investigating QI impl can you bolt a simple IDispatch tear-off object that handles DISPID_NEWENUM only so that this code works

    Code:
      For Each V In Arr.NewEnum '<- has an IDispatch that returns itself on DISPID_NEWENUM
        Debug.Print V
      Next
    The idea is for a dictionary replacement to be able to use separate enumerators for both keys and values like this

    Code:
      For Each V In oDict.Keys
        Debug.Print "Key=" & V
      Next
    
      For Each V In oDict.Items
        Debug.Print "Item=" & V
      Next
    
      For Each V In oDict
        Debug.Print "Tuple=(" & V(0) & ", " & V(1) & ")"
      Next
    cheers,
    </wqw>

  14. #14
    PowerPoster
    Join Date
    Jun 2013
    Posts
    4,574

    Re: [RESOLVED] Is it possible to add an enumerator to an array?

    Quote Originally Posted by wqweto View Post
    Just fiddled a bit with the RC5 enumerator impl and found that the following line brings the IDE down
    Debug.Print TypeName(Arr.NewEnum)
    Thanks, should be fixed now, in new version 5.0.75
    ...(when you download - please re-register on your dev-machines despite being BinCompatible, because of new Interface- and Class-additions in RC5)

    Quote Originally Posted by wqweto View Post
    While you at it investigating QI impl can you bolt a simple IDispatch tear-off object that handles DISPID_NEWENUM ...
    Ok, done...
    New version 5.0.75 now contains the complete functionality (+ a few extra-helpers) of what was shown here.
    http://www.vbforums.com/showthread.p...BaseInterfaces
    (the above line offers the Sources for a Dll which supports Base-Interface-SubClassing in a VB-Friendly manner).

    An RC5-adapted Tutorial-Folder-Stack which demonstrates that functionality, is now available here:
    TutorialApps_RC5.VBI.zip

    For your outlined usecase, the Tutorial-Folder: 4 - MultiEnumerations per vbIEnumerable
    should offer appropriate code...

    @dreammanor
    FWIW... cArrayList now got For Each support built-in as well...

    HTH

    Olaf

  15. #15
    Frenzied Member
    Join Date
    Aug 2010
    Location
    Canada
    Posts
    1,562

    Re: [RESOLVED] Is it possible to add an enumerator to an array?

    Nice work Olaf - There's been a couple of times I wished the cArrayList was enumerable, and now it is

  16. #16
    Frenzied Member wqweto's Avatar
    Join Date
    May 2011
    Posts
    1,720

    Re: [RESOLVED] Is it possible to add an enumerator to an array?

    Quote Originally Posted by Schmidt View Post
    For your outlined usecase, the Tutorial-Folder: 4 - MultiEnumerations per vbIEnumerable
    Using vbIEnumerable now both

    For Each V In Arr

    . . . and

    For Each V In Arr.NewEnum

    . . . work. Great!

    cheers,
    </wqw>

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Featured


Click Here to Expand Forum to Full Width