Rekcs
Rekcs

Reputation: 887

Add multiple attachments using Properties

I created this property in order to add more than one attachment:

Private ReadOnly Index As Integer
Private mAttachments(1 To 10) As String
Private ReadOnly NewAttachment As String

Public Property AddAttachment() As String
    Get
        If Index >= 1 And Index <= UBound(mAttachments) Then
            AddAttachment = mAttachments(Index)
        End If
        Return mAttachments(Index)
    End Get

    Set
        If Index >= 1 And Index <= UBound(mAttachments) Then
            mAttachments(Index) = NewAttachment
        Else
            MessageBox.Show("Error")
        End If
    End Set
End Property

To test it the call I used this two files, but I am receiving emails without the attachments. Can't understand what I might be doing wrong.

 mAttachments(0) = "C:\teste.txt"
 mAttachments(1) = "C:\teste2.txt"

Upvotes: 0

Views: 149

Answers (1)

Jimi
Jimi

Reputation: 32248

You should probably have a dedicated class to handle the Attachments list.

Option 1:
If you want to keep the array, you make this work overloading an indexed Property.

The non-indexed Property returns a copy of the array to force the consumers to use your property to change values in the array (since a copy is returned, any change will only apply to the copy, not the original array which handles errors).

The m_MaxAttachments Field is not strictly necessary. You can use the Array.Length.
You cannot directly replace the Array with a List(Of String) with this setup.

Private ReadOnly m_MaxAttachments As Integer = 10
Private ReadOnly m_Attachments(m_MaxAttachments - 1) As String

Public ReadOnly Property MaxAttachments As Integer = m_MaxAttachments

Public ReadOnly Property Attachments As String()
    Get
        Return m_Attachments.Select(Function(s) s).ToArray()
    End Get
End Property

Public Property Attachments(index As Integer) As String
    Get
        If index < 0 OrElse index >= m_MaxAttachments Then
            AttachmentError(index)
            Return String.Empty
        End If
        Return m_Attachments(index)
    End Get
    Set
        If index >= 0 AndAlso index < m_MaxAttachments Then
            m_Attachments(index) = Value
        Else
            AttachmentError(index)
        End If
    End Set
End Property

Private Sub AttachmentError(value As Integer)
    MessageBox.Show($"Index out of range: {value} Valid range: [0, {m_MaxAttachments - 1}]")
End Sub

Now you can use the indexer to Get/Set a value from/to the underlying Array of strings or iterate a copy of the collection using the non-indexed Property. E.g.:

Attachments(0) = "[Some Path]"
Attachments(1) = "[Other Path]"
Attachments(10) = "[10th Path]" '<- A MessageBox informs that the index is out of range

Option 2:
Use a Class object to handle a List(Of String) and let the Public Property just act as a mediator.
The class exposes methods that allow to add/remove/iterate (this last is left to you, to implement if needed; the overloaded indexed Property, moved to the class, only returns a ReadonlyCollection or an indexed value).

Imports System.Collections.ObjectModel

Private ReadOnly Property m_Attachments As MyAttachments = New MyAttachments()

Public ReadOnly Property Attachments As MyAttachments
    Get
        Return m_Attachments
    End Get
End Property

Public Property Attachments(index As Integer) As String
    Get
        Return m_Attachments.Values(index)
    End Get
    Set
        If index >= 0 AndAlso index < MyAttachments.MaxAttachments Then
            m_Attachments.Values(index) = Value
        End If
    End Set
End Property

So you can write:

Attachments.Add("Some Path 1")
Attachments.Add("Some Path 2")
Attachments.Add("Some Path 3")

Attachments.Clear()
Attachments.Add("New Path")

' If you add more items than the max Capacity, it will return 
' the number of strings added to the List
Dim Items Added = Attachments.AddRange([Some IEnumerable(Of String)])

Attachments.Remove("New Path")
Attachments.RemoveAt(0)

and so on.

Handler Class:

Public Class MyAttachments
    Private Shared ReadOnly m_MaxCount As Integer = 10
    Private ReadOnly m_Values As New List(Of String)(m_MaxCount)

    Public Shared ReadOnly Property MaxAttachments As Integer = m_MaxCount

    Public ReadOnly Property Values As ReadOnlyCollection(Of String)
        Get
            Return m_Values.AsReadOnly()
        End Get
    End Property

    Public Property Values(index As Integer) As String
        Get
            Return m_Values(index)
        End Get
        Set
            If index >= 0 AndAlso index < MaxAttachments Then
                m_Values(index) = Value
            End If
        End Set
    End Property

    Public Sub Add(value As String)
        If m_Values.Count < m_Values.Capacity Then
            m_Values.Add(value)
        End If
    End Sub

    Public Function AddRange(values As IEnumerable(Of String)) As Integer
        Dim startItemsCount = m_Values.Count
        Dim indexer = startItemsCount
        For Each value As String In values
            If indexer >= m_MaxCount Then Exit For
            Add(value)
            indexer += 1
        Next
        Return indexer - startItemsCount
    End Function

    Public Sub Remove(value As String)
        m_Values.Remove(value)
    End Sub

    Public Sub RemoveAt(index As Integer)
        If index >= 0 AndAlso index < m_Values.Count Then
            m_Values.RemoveAt(index)
        End If
    End Sub
    Public Sub RemoveRange(indexes As Integer())
        For Each index As Integer In indexes
            RemoveAt(index)
        Next
    End Sub
    Public Sub RemoveRange(values As String())
        For Each value As String In values
            Remove(value)
        Next
    End Sub
    Public Sub Clear()
        m_Values.Clear()
    End Sub
    Public ReadOnly Property Count As Integer
        Get
            Return m_Values.Count
        End Get
    End Property
End Class

Upvotes: 1

Related Questions