IEnumerable shows up in COM but not ICollection?
I have a bunch of dictionary (Integer, SomeClass) in my main class which I am using AutoDual for COM. Users need to iterate over instances in VBA (Excel specific), so I have a group of them in my main class ...
Public ReadOnly Property Inflations() As IEnumerable
Get
Return InflationsDict.Values
End Get
End Property
I can use this in my VBA code like this ...
For Each I In CP.Inflations...
But it doesn't support the graph. Dictionaries also expose an ICollection that has a .Count, but when I made this one change ...
Public ReadOnly Property Inflations() As ICollection
the method disappears from COM and the same one for each gets "Runtime Error 438 Object does not support this property or method". It continues to work great on VB.net.
I was told that the basic rule is that non-generics should export OK. Nothing comes up at compile time - when I tried to export IEnumerable(Of Inflation)
to the lark, a warning will probably appear in the output.
Is there a sidebar rule that applies in this case?
source to share
I can say that I have posted some misleading comments. The problem you are having is that the elements of the ICollection will display, but its inherited interface (IEnumerable) is not. This breaks the ability to iterate through the collection.
Let's write an interface for the dictionary. I will guess options:
<ComVisible(True)> _
<InterfaceType(ComInterfaceType.InterfaceIsDual)> _
Public Interface IMyDictionary
ReadOnly Property Count As Integer
Function Contains(ByVal key As Object) As Boolean
<DispId(0)> Property Item(ByVal key As Object) As Object
<DispId(-4)> Function GetEnumerator() As System.Collections.IEnumerator
End Interface
With an example implementation:
<ComVisible(True)> _
<ClassInterface(ClassInterfaceType.None)> _
<ProgId("StackOverflow.Example")> _
Public Class Example
Implements IMyDictionary
Private collection As New Dictionary(Of Integer, String)
Public Sub New()
collection = New Dictionary(Of Integer, String)
'' Add some sample data
collection.Add(1, "one")
collection.Add(2, "two")
collection.Add(3, "three")
End Sub
Public ReadOnly Property Count As Integer Implements IMyDictionary.Count
Get
Return collection.Count
End Get
End Property
Public Function GetEnumerator() As IEnumerator Implements IMyDictionary.GetEnumerator
Return CType(collection.Values, System.Collections.IEnumerable).GetEnumerator()
End Function
Public Property Item(ByVal key As Object) As Object Implements IMyDictionary.Item
Get
Return collection(CInt(key))
End Get
Set(ByVal value As Object)
collection(CInt(key)) = CStr(value)
End Set
End Property
Public Function Contains(key As Object) As Boolean Implements IMyDictionary.Contains
Return collection.ContainsKey(CInt(key))
End Function
End Class
An example VBScript that uses it:
Set obj = CreateObject("StackOverflow.Example")
WScript.Echo "Count=" & obj.Count
WScript.Echo "Value for key 2=" & obj(2)
WScript.Echo "Contains(3)=" & obj.Contains(3)
WScript.Echo "Contains(42)=" & obj.Contains(42)
WScript.Echo "Values:"
For Each elem in obj
WScript.Echo " " & elem
Next
Output:
Count=3
Value for key 2=two
Contains(3)=True
Contains(42)=False
Values:
one
two
three
source to share