2015-06-20 2 views
5

Ho una collezione che uso per avere una mappa String -> MailItem. Riempio la mappa e quando trovo una chiave duplicata voglio leggere l'elemento nella raccolta.Perché non riesco a ottenere un oggetto da una Collezione e memorizzarlo in una variabile?

Sembra così facile, ma ho impiegato più di un'ora a cercare di capire perché non è possibile assegnare un elemento Raccolta a una variabile locale. (Vedi PROBLEM nel codice di seguito)

oMailOther = cMails.Item(cMailKey) "Oggetto variabile o variabile del blocco non set"

Set oMailOther = cMails.Item(cMailKey) "Oggetto richiesto"

L'altra cMails(cMailKey) forma dà lo stesso errore. Spostare la Dim in giro non fa alcuna differenza. cMails deve essere disponibile perché è stato utilizzato in precedenza nel metodo. Nota la riga Debug.Print appena prima di questa istruzione, che funziona. Cosa mi manca?

Option Explicit 
Option Compare Text 

Public cMails As Collection 

Public Sub GetOutlookAttachments() 
    Set cMails = New Collection 

    Dim oStore As Store 
    For Each oStore In Session.Stores 
     If oStore.DisplayName = "Outlook Data File" Then 
      ProcessFolder oStore.GetRootFolder() 
     End If 
    Next 
End Sub 

Private Sub ProcessFolder(oFolder As Folder) 
    Debug.Print oFolder.FolderPath 
    ProcessItems oFolder.Items 

    Dim oSubFolder As Folder 
    For Each oSubFolder In oFolder.Folders 
     ProcessFolder oSubFolder ' recurse 
    Next 
End Sub 

Private Sub ProcessItems(oItems As Items) 
    Dim oItem As Object 
    For Each oItem In oItems 
     DoEvents 
     If TypeOf oItem Is MailItem Then 
      Dim oMail As MailItem 
      Set oMail = oItem 
      Dim cMailKey As String 
      cMailKey = oMail.ConversationID & "-" & oMail.ConversationIndex 
      If Not Contains(cMails, cMailKey) Then 
       cMails.Add oMail.Subject, cMailKey 
      Else 
       Debug.Print cMails.Item(cMailKey) 
       Dim oMailOther As MailItem 
PROBLEM  oMailOther = cMails.Item(cMailKey) 
       Debug.Print cMailKey & ": " & oMailOther.Subject 
      End If 
     ElseIf TypeOf oItem Is MeetingItem Then 
      ' ignore 
     Else 
      Debug.Print "oItem Is a " & TypeName(oItem) 
     End If 
    Next oItem 
End Sub 

Public Function Contains(col As Collection, key As Variant) As Boolean 
    Dim obj As Variant 
    On Error GoTo err 
    Contains = True 
    obj = col(key) 
    Exit Function 
err: 
    Contains = False 
End Function 

Ho anche cercato di replicare simili Add e Item chiamate altrove e funziona.

Public Sub Test() 
    Set cMails = New Collection 

    Dim cMailKey As String 
    cMailKey = "hello" 
    cMails.Add Session.Stores.Item(1), cMailKey 

    Debug.Print cMails(cMailKey) 
    Dim oStore As Store 
    Set oStore = cMails(cMailKey) 
    Debug.Print oStore.DisplayName 
End Sub 
+1

Provare a utilizzare 'CreateObject (" Scripting.Dictionary ")' invece di 'Collection'. Il dizionario ha il metodo nativo '.Exists()', quindi non è necessario 'Function Contains()'. – omegastripes

+0

@omegastripes Lo so, ma quella parte funziona bene, altrimenti non arriverebbe alla riga 'PROBLEM'. Non voglio ulteriori dipendenze. – TWiStErRob

+0

Non sono sicuro che considererei 'Scripting.Dictionary 'una dipendenza problematica - richiederebbe che * non * sia disponibile sul computer di destinazione. – Comintern

risposta

6

Ho copiato il codice e fatto funzionare. La collezione cMails che si sta creando è una raccolta di Strings, non di oggetti di posta; tuttavia, oMailOther viene dichiarato come Object di tipo MailItem.

Nel tuo compito senza la parola chiave Set, VB si lamenta che desideri assegnare qualcosa a un oggetto (lato sinistro) e utilizzare la parola chiave Set. Ora, con la parola chiave Set, VB lamenta che il lato destro non è un oggetto ...

Per effettuare cMails in un colection di elementi di posta elettronica, modificare l'istruzione Add come segue:

cMails.Add oMail, cMailKey 

(vale a dire non aggiungi oMail.Subject ma l'intera oMail oggetto.)

Ora utilizzare la parola chiave Set in Set oMailOther = cMails.Item(cMailKey) e tutto funziona bene.

+0

Come hai visto questo: "è una raccolta di stringhe"? (oltre a notare il '.Subject' a' .Add'). – TWiStErRob

+0

Ho impostato un orologio su "oMail" e ho controllato gli articoli e ho visto che erano stringhe, come altri hanno notato attraverso l'analisi. –

+0

È così strano che non si può dire "MailItem richiesto", come la maggior parte delle lingue sane (InvalidCastException, ClassCastException). – TWiStErRob

2

oMailOther è un MailItem, quindi senza una domanda è necessario utilizzare Set quello di assegnarlo a una variabile:

Set oMailOther = cMails(cMailKey) 

Tuttavia la vostra collezione cMails non contiene un oggetto MailItem. Contiene solo i soggetti (ovvero le stringhe anziché gli oggetti) precedentemente aggiunti con .

A quanto pare intendeva cMails.Add oMail, cMailKey.

1

Il problema non è come si è recupero le voci, è come si sta aggiungendo loro:

If Not Contains(cMails, cMailKey) Then 
    cMails.Add oMail.Subject, cMailKey 
Else 

s' Collection.Add primo parametro è quello che si archiviano nella collezione - in questo caso l'oggetto. Quando si sta tentando di recuperare gli elementi della collezione qui ...

Debug.Print cMails.Item(cMailKey) 
Dim oMailOther As MailItem 
MailOther = cMails.Item(cMailKey) 
Debug.Print cMailKey & ": " & oMailOther.Subject 

... si sta cercando di recuperare l'oggetto in sé. Il Debug.Print funziona perché hai una collezione piena di stringhe.

Se avete bisogno di una raccolta di MailItem, è necessario compilare in questo modo:

cMails.Add oMail, cMailKey