Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations strongm on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Initialize/Set with either an array or delimited string 2

Status
Not open for further replies.

RustyAfro

Programmer
Jan 12, 2005
332
US
Hello,

I want to make a class that requires a variable of email addresses upon initialization. The class should be able to parse an array of email addresses into a semicolon delimited string OR just accept an already pre-parsed string of semicolon delimited emails.

I'm trying to figure out the best practice on how to implement this when initializing the class. I wrote some code below that I think would work but I can't figure out how to make a property where the calling code could change the emails again after the initialization, with either a string or an array. I tried overloading the "Set" in a property but I am only allowed one Set, so I left it ReadOnly for now. Any thoughts are really appreciated! ;-)

Code:
        Public _Recipients As String

        'Created 2 constructers, one to accept an array the other to accept a string
        Public Sub New(ByVal Recipients() As String)
            _Recipients = "" 'Will write some code to parse the array into a delimited string
        End Sub

        Public Sub New(ByVal Recipients As String)
            _Recipients = Recipients
        End Sub

        ReadOnly Property Recipients() As String
            Get
                Return _Recipients
            End Get
        End Property
    End Class

 
Remove the ReadOnly word:
Code:
Public Class Class1
   Private _Recipients As String()
   Public Property Recipients() As String()
      Get
         Return _Recipients
      End Get
      Set(ByVal value As String)
         _Recipients = value
      End Set
   End Property
End Class

In addition, you can remove the [blue]ByVal Recipients() As String[/blue] in the New sub.

Once you create an instance of it, simply set its Recipients property.

Regards.
 
That didn't seem to work for me. If I try to pass an array of string emails to the Property, I get an error that the array cannot be converted to string.

The goal for me is to let the class accept either an array or a string from the calling code and let the class take care of converting the array into a string. Hence why I did sub New(). I guess I'm looking for two separate Properties but was looking for a best practice solution.
 
Code:
 Private Sub btnLoadByArray_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnLoadByArray.Click
        Dim recipients As String() = New String() {"bill.gates@microsoft.com", "steve.jobs@apple.com"}
        Dim sc As New SomeClass(recipients, ";")
        MessageBox.Show(sc.Recipients)
    End Sub


    Private Sub btnLoadByString_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnLoadByString.Click
        Dim recipients As String = "bill.gates@microsoft.com;steve.jobs@apple.com"
        Dim sc As New SomeClass(recipients)
        MessageBox.Show(sc.Recipients)
    End Sub
End Class


Class SomeClass
    Public _Recipients As String

    'Created 2 constructers, one to accept an array the other to accept a string
    Public Sub New(ByVal Recipients() As String, ByVal Delimeter As String)
        _Recipients = ""
        For i As Integer = 0 To Recipients.Length - 1
            Dim s As String = Recipients(i)
            _Recipients &= s
            If Not i = Recipients.Length - 1 Then _Recipients &= Delimeter
        Next
    End Sub

    Public Sub New(ByVal Recipients As String)
        _Recipients = Recipients
    End Sub

    ReadOnly Property Recipients() As String
        Get
            Return _Recipients
        End Get
    End Property
End Class
 
Thanks for that, its basically what I did as well.

If the calling code needs to change the emails on a second call of the same class isnstance, should I just make two separate properties, one with a SET for an array and one for a string?
 
Fiddling with this I found that using an Object seems like it might work. Anything wrong with going this route? I think it would be weakly typed and doesn't allow me to restrict to only an array or string but it's the only thing I can think of other than creating a differently named SET property.

Code:
        Public Property [TO]() As Object
            Get
                Return _TO
            End Get
            Set(ByVal Value As Object)
                If TypeOf (Value) Is Array Then
                    _TO = String.Join(";", Value)
                Else
                    _TO = Value
                End If
            End Set
        End Property
 
Hmmm, maybe you can throw an exception if an object of a different type than your two valid types are passed in.
 
Declaring the properties type as an Object is an interesting work-around.

For this type of situation, I'll define overloaded Setxxxxxx subroutines ...
Code:
Public Class SomeClass

    Private mRecipients As String

    Public ReadOnly Property Recipients() As String
        Get
            Return mRecipients
        End Get
    End Property

    Public Sub SetRecipients(ByVal recipients As String)
        mRecipients = recipients
    End Sub

    Public Sub SetRecipients(ByVal recipients() As String)
        mRecipients = String.Join(";", recipients)
    End Sub

End Class
 
Hi Dave,

In the end I used overloading as well since I didn't like having an error at runtime if a non-string or non-array was passed in; I'd rather have an error in development/debug.

The only different thing I did different from yours is kill the property all together and made three overloaded [TO] methods, 1 a function to handle the Get and 2 subs to handle the different Sets for a string and an array. It seems to work ok. Below is a snippet of the class. Still open to any suggestions, I'm just refreshing on coding (been out of practice for awhile!)

Still, it was interesting getting the property to do it too!

Code:
Public Class Email

Private Email As New MailMessage
Private _EmailDelimiter As String = ";" 

   Public Function [TO]() As String
        Return Email.To.ToString
    End Function

    Public Sub [TO](ByVal value As String)
        If value <> "" Then 'If Blank Do nothing
            For Each emailAddress As String In value.Split(_EmailDelimiter)
                Email.To.Add(New MailAddress(emailAddress))
            Next
        End If
    End Sub

    Public Sub [TO](ByVal value() As String)
        For Each emailAddress As String In value
            Email.To.Add(New MailAddress(emailAddress))
        Next
    End Sub
End Class

 
One suggestion would be that when you're overloading methods, minimize redundant code by directing the processing to a single method. That way, if the functionality changes, you need only make the change in one place. For example, the first sub could be written as:
Code:
Public Sub [TO](ByVal value As String)
    If value <> "" Then Me.TO(value.Split(_EmailDelimiter))
End Sub
I agree with your changing the ReadOnly property to a function - it seems more consistent.
 
Nice, I didn't realize I could pass an array directly to the .TO collection. I'm happy to kill the loop!

Thanks, and a star for you too!
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top