2015-06-05 3 views
3

У меня есть куча словаря (Integer, SomeClass) в моем основном классе, который я использую AutoDual для COM. Пользователи должны перебрать экземпляры в VBA (Excel специально), так что у меня есть куча из них это в моем главном классе ...IEnumerable видна в COM, но не ICollection?

Public ReadOnly Property Inflations() As IEnumerable 
    Get 
     Return InflationsDict.Values 
    End Get 
End Property 

я могу использовать это в моем коде VBA, как это ...

For Each I In CP.Inflations... 

Но это не поддерживает граф. Словари разоблачить ICollection, а также, который имеет .Count, но когда я сделал это единственное изменение ...

Public ReadOnly Property Inflations() As ICollection 

метод исчезает из COM, и тот же для каждого становится «Ошибка выполнения 438 Объект не поддерживайте это свойство или метод ». Он продолжает отлично работать на VB.net.

Мне сказали, что основным правилом является то, что не-generics должны экспортировать ОК. Во время компиляции ничего не возникает - тогда, когда я пытался экспортировать IEnumerable(Of Inflation) на жаворонку, наверняка на выходе появится предупреждение.

Есть ли боковая панель правила, которое применяется в этом случае?

ответ

1

Я могу сказать, что я публиковал некоторые вводящие в заблуждение комментарии. Проблема, с которой вы сталкиваетесь, заключается в том, что элементы ICollection будут отображаться, но его унаследованный интерфейс (IEnumerable) не является. Это нарушает способность итерации коллекции.

Давайте напишем интерфейс для словаря. Я буду считать варианты:

<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 

С реализацией образца:

<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 

Образец VBScript, который осуществляет его:

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 

Выход:

Count=3 
Value for key 2=two 
Contains(3)=True 
Contains(42)=False 
Values: 
    one 
    two 
    three 
+0

Хорошо, я * думаю * я понимаю, что здесь происходит. К счастью, у меня есть идеальный класс, чтобы связать это, словари фактически изолированы в табличной конструкции, которая делает это простым. Но вопрос о наследовании ... как правило, имеет наследование интерфейса * не * выставлять унаследованные методы? Или есть немного хитрости к этому? –

+0

Существует несколько проблем, но основная проблема заключается в том, что существует много COM-клиентов, которые не поддерживают класс с несколькими интерфейсами. Они могут использовать только [ComDefaultInterface] и не имеют способа попросить другого. Ограничение на языках сценариев, VBA, VB6, у них вообще нет понятия интерфейсов. Технический обходной путь для этого состоит в том, чтобы выставить два члена, один из которых возвращает ICollection, а другой - для возврата IEnumerable. Не красиво. –

+0

Что заставляет меня беспокоиться, что, возможно, я был в тупике с интерфейсами, но я реализовал это, и я немного поиграл, чтобы понять, что это делает для общего API в тех программах, которые его потребляют. –

Смежные вопросы