patternModerate
Wait, is this... LINQ?
Viewed 0 times
thislinqwait
Problem
Context
I'm working on a little project that consists in a series of Microsoft Excel add-ins (.xlam). The code being submitted for review here, is located in the
Feel free to comment on the project architecture, but I'm mostly interested in the
Linq?
Ok not exactly linq, but very much inspired by System.Linq.Enumerable, and only made possible with the Reflection.Delegate class. I'm working on a
The Object Explorer displays a mini-documentation for the selected method because I've added hidden
Here's the whole class, with the attributes:
```
VERSION 1.0 CLASS
BEGIN
MultiUse = -1 'True
END
Attribute VB_Name = "LinqEnumerable"
Attribute VB_GlobalNameSpace = False
Attribute VB_Creatable = False
Attribute VB_PredeclaredId = True
Attribute VB_Exposed = True
Private encapsulated As New Collection
Option Explicit
Private Function EquateReferenceTypes(value As Variant, other As Variant) As Boolean
Dim equatable As IEquatable
If TypeOf value Is IEquatable Then
Set equatable = value
EquateReferenceTypes = equatable.Equals(other)
Else
EquateReferenceTypes = (ObjPtr(value) = ObjPtr(other))
End If
End Function
Private Function EquateValueTypes(value As Variant, other As Variant) As Boolean
EquateValueTypes = (value = other)
End Function
Friend Sub Add(ParamArray values())
Dim valuesArray() As Variant
valuesArray = values
AddArray valuesArray
End Sub
Friend Sub Concat(ByVal values As LinqEnumerable)
AddArray values.ToArray
End Sub
Friend Sub AddArray(values() As Variant)
Dim value As Variant, i As Long
For i = LBound(values) To UBound(values)
encapsulated.Add values(i)
Next
End Sub
Public Property Get Item(ByVal index A
I'm working on a little project that consists in a series of Microsoft Excel add-ins (.xlam). The code being submitted for review here, is located in the
Reflection project:Feel free to comment on the project architecture, but I'm mostly interested in the
Reflection.LinqEnumerable class.Linq?
Ok not exactly linq, but very much inspired by System.Linq.Enumerable, and only made possible with the Reflection.Delegate class. I'm working on a
Grouping class that will enable adding a GroupBy method in there... but for now these are the members of the LinqEnumerable class:The Object Explorer displays a mini-documentation for the selected method because I've added hidden
VB_Description attributes for every public method.Here's the whole class, with the attributes:
```
VERSION 1.0 CLASS
BEGIN
MultiUse = -1 'True
END
Attribute VB_Name = "LinqEnumerable"
Attribute VB_GlobalNameSpace = False
Attribute VB_Creatable = False
Attribute VB_PredeclaredId = True
Attribute VB_Exposed = True
Private encapsulated As New Collection
Option Explicit
Private Function EquateReferenceTypes(value As Variant, other As Variant) As Boolean
Dim equatable As IEquatable
If TypeOf value Is IEquatable Then
Set equatable = value
EquateReferenceTypes = equatable.Equals(other)
Else
EquateReferenceTypes = (ObjPtr(value) = ObjPtr(other))
End If
End Function
Private Function EquateValueTypes(value As Variant, other As Variant) As Boolean
EquateValueTypes = (value = other)
End Function
Friend Sub Add(ParamArray values())
Dim valuesArray() As Variant
valuesArray = values
AddArray valuesArray
End Sub
Friend Sub Concat(ByVal values As LinqEnumerable)
AddArray values.ToArray
End Sub
Friend Sub AddArray(values() As Variant)
Dim value As Variant, i As Long
For i = LBound(values) To UBound(values)
encapsulated.Add values(i)
Next
End Sub
Public Property Get Item(ByVal index A
Solution
Decomposition
There are redundancies in translating from
Consider these three snippits
They all do the same thing. Why translate from
All of those methods did the same thing, but expected different inputs. Duck-typing is one of the few high-level features that VBA does right. It's a shame to not take advantage of it.
You can keep them if you want to enforce type safety, but I wouldn't. You need to add a two new methods for every other container you want to support. Honestly, I would just dump all but
There are redundancies in translating from
Array and Collection.Consider these three snippits
Dim value As Variant, i As Long 'value is unused?
For i = LBound(values) To UBound(values)
encapsulated.Add values(i)
NextDim value As Variant
For Each value In values
result.Add value
NextSet result = LinqEnumerable.FromArray(value.ToArray)They all do the same thing. Why translate from
LinqEnumerable to Array just to go back to LinqEnumerable? Why have a separate method for adding an Array or Enumerable when the same procedure works for both?Private Sub Extend(ByVal sequence As Variant)
Dim element As Variant
For Each element in sequence
encapsulated.Add element
Next element
End Sub
Friend Sub Add(ParamArray values() As Variant)
Extend values
End Sub
Friend Sub Concat(ByVal values As LinqEnumerable)
Extend values
End Sub
Friend Sub AddArray(values() As Variant)
Extend values
End Sub
' Optional New methods
Friend Sub AddCollection(ByVal values As VBA.Collection)
Extend values
End Sub
Friend Sub AddList(ByVal values As System.List)
Extend values
End SubAll of those methods did the same thing, but expected different inputs. Duck-typing is one of the few high-level features that VBA does right. It's a shame to not take advantage of it.
Public Function FromCollection(ByVal values As VBA.Collection) As LinqEnumerable
Attribute FromCollection.VB_Description = "Creates a new instance by copying elements of a VBA.Collection instance."
Dim result As New LinqEnumerable
result.AddCollection values
Set FromCollection = result
End Function
Public Function FromEnumerable(ByVal values As System.Enumerable) As LinqEnumerable
Attribute FromEnumerable.VB_Description = "Creates a new instance by copying elements of a System.Enumerable instance."
Dim result As LinqEnumerable
result.Concat values
Set FromEnumerable = result
End Function
Public Function FromList(ByVal values As System.List) As LinqEnumerable
Attribute FromList.VB_Description = "Creates a new instance by copying elements of a System.List instance."
Dim result As New LinqEnumerable
result.AddList values
Set FromList = result
End Function
Public Function FromArray(ByVal values() As Variant) As LinqEnumerable
Attribute FromList.VB_Description = "Creates a new instance by copying elements of a System.List instance."
Dim result As New LinqEnumerable
result.AddArray values
Set FromList = result
End FunctionYou can keep them if you want to enforce type safety, but I wouldn't. You need to add a two new methods for every other container you want to support. Honestly, I would just dump all but
Extend and Add and make Extend Friend, then create just these two methods.Friend Sub Extend(ByVal sequence As Variant)
Dim element As Variant
For Each element in sequence
encapsulated.Add element
Next element
End Sub
Friend Sub Add(ParamArray values() As Variant)
Extend values
End Sub
Public Function Create(ParamArray values() As Variant) As LinqEnumerable
Set Create = CreateFrom(values)
End Function
Public Function CreateFrom(ByVal values As Variant) As LinqEnumerable
Dim result As New LinqEnumerable
result.Extend values
Set CreateFrom = result
End FunctionCode Snippets
Dim value As Variant, i As Long 'value is unused?
For i = LBound(values) To UBound(values)
encapsulated.Add values(i)
NextDim value As Variant
For Each value In values
result.Add value
NextSet result = LinqEnumerable.FromArray(value.ToArray)Private Sub Extend(ByVal sequence As Variant)
Dim element As Variant
For Each element in sequence
encapsulated.Add element
Next element
End Sub
Friend Sub Add(ParamArray values() As Variant)
Extend values
End Sub
Friend Sub Concat(ByVal values As LinqEnumerable)
Extend values
End Sub
Friend Sub AddArray(values() As Variant)
Extend values
End Sub
' Optional New methods
Friend Sub AddCollection(ByVal values As VBA.Collection)
Extend values
End Sub
Friend Sub AddList(ByVal values As System.List)
Extend values
End SubPublic Function FromCollection(ByVal values As VBA.Collection) As LinqEnumerable
Attribute FromCollection.VB_Description = "Creates a new instance by copying elements of a VBA.Collection instance."
Dim result As New LinqEnumerable
result.AddCollection values
Set FromCollection = result
End Function
Public Function FromEnumerable(ByVal values As System.Enumerable) As LinqEnumerable
Attribute FromEnumerable.VB_Description = "Creates a new instance by copying elements of a System.Enumerable instance."
Dim result As LinqEnumerable
result.Concat values
Set FromEnumerable = result
End Function
Public Function FromList(ByVal values As System.List) As LinqEnumerable
Attribute FromList.VB_Description = "Creates a new instance by copying elements of a System.List instance."
Dim result As New LinqEnumerable
result.AddList values
Set FromList = result
End Function
Public Function FromArray(ByVal values() As Variant) As LinqEnumerable
Attribute FromList.VB_Description = "Creates a new instance by copying elements of a System.List instance."
Dim result As New LinqEnumerable
result.AddArray values
Set FromList = result
End FunctionContext
StackExchange Code Review Q#66706, answer score: 15
Revisions (0)
No revisions yet.