none
Way to return several values from a function or similar depending on ID supplied RRS feed

  • Question

  • Hi

    Firstly my title may be a bit vague here as I know what I am trying to acheive, but it is not so easy to explain to others, and I can't see where I am going wrong in my coding logic

    I will try and explain this as best I can:

    Basically in my app it will loop through a series of items in a list (event log entries) and add them to a database, but just storing the information I need - don't think what it is e.g. event log data is really relevant to the problem/question though

    So as I loop through I need to call a function? passing an ID number (integer) and it then returns several results for me to store

    so lets say I pass it 1102 then it needs to return several different values and I then add each of them to my database

    As I say this is hard to explain, but I currently have a class containing my values I want returning - has many items in it, but shortened version shown

     Public Class ExtractedEventData
            Public Property ShortMessage As String
            Public Property SubjectUserName As String
            Public Property IpAddress As String
        End Class

    So I thought perhaps I could call a function passing the ID and then it returns all the values depending on what ID I passed e.g.

     Private Function GetEventData(ByVal EventID As Integer)
            Dim results As ExtractedEventData
    
            Select Case EventID
                Case 1102
                    results.ShortMessage = "The audit log was cleared"
                    results.SubjectUserName = "ddd"
                    results.IpAddress = "aaa"
            End Select
    
            Return results
        End Function


    then I could call it as below and then get access to all results for ID I passed:-

     Dim results = GetEventData(1102)
            MsgBox(results.ShortMessage)
            ...

    I have been looking at this so long that I am going round in circles and probably missing a much easier/better way to do it - so thought I would ask

    In past I have used Function to just return one value, but since I need several values back I thought using class etc was correct way

    Open to comments, suggestions, criticisms etc

    And please ask if doesn't make any sense at all


    Darren Rose

    Saturday, September 2, 2017 1:35 PM

Answers

  • Yes which is what I had thought I had done above in my example which causes an error

    The Public Class ExtractedEventData contains all my properties

    ???


    Darren Rose

    I see that now, but I don't see where you create a NEW instance of the class.

    That's imperative.

    With a structure you don't have to but with a class it's not optional.

    ***** EDIT *****

    Copying yours and trying to modify it on the fly here:

        Private Function GetEventData(ByVal EventID As Integer)
            Dim results As ExtractedEventData = Nothing
    
            Select Case EventID
                Case 1102
                    results = New ExtractedEventData
                    results.ShortMessage = "The audit log was cleared"
                    results.SubjectUserName = "ddd"
                    results.IpAddress = "aaa"
            End Select
    
            Return results
        End Function

    You can (and I would) put those property settings in an initializer with the "With" keyword.


    "A problem well stated is a problem half solved.” - Charles F. Kettering



    • Edited by Frank L. Smith Saturday, September 2, 2017 4:09 PM ...formatted text
    • Marked as answer by wingers Wednesday, September 13, 2017 9:34 AM
    Saturday, September 2, 2017 3:57 PM

All replies

  • So forgetting all context I want to pass a value/ID as integer to a function (or similar) and it return various bits of information depending on the ID I supplied

    I then need to access those values easily to shown on form or add to database or whatever I do with them

    So I pass say 1002 to a function and then it returns results stored in a class (or similar) which I can then easily access with something like - results.firstname, results.surname, results.age, results.message etc etc


    Darren Rose

    Saturday, September 2, 2017 1:56 PM
  • Darren,

    I'm not clear on what the question is, but in general -- to return several objects with a function call, the return type needs to be an instance of a class or structure.

    Is that what you're asking or did I misunderstand?


    "A problem well stated is a problem half solved.” - Charles F. Kettering

    Saturday, September 2, 2017 3:03 PM
  • Hi Frank

    Yes sorry I struggled to explain

    But basically I need to pass a value (integer) to a function and then return several other values to then use elsewhere

    Think of it perhaps in this context - where you pass a NAME to a function and then it returns address, state, country, zip code, phone number etc back - but all as separate strings so I can access them separately


    Darren Rose

    Saturday, September 2, 2017 3:30 PM
  • Hi Frank

    Yes sorry I struggled to explain

    But basically I need to pass a value (integer) to a function and then return several other values to then use elsewhere

    Think of it perhaps in this context - where you pass a NAME to a function and then it returns address, state, country, zip code, phone number etc back - but all as separate strings so I can access them separately


    Darren Rose

    Then return an instance of the class. ;-)

    Seriously, set up a class that has those bits of data as properties (address, state, country, zip code, phone number) and that's how you access them individually.

    The logic inside the class (that has this function) is where the work is, but that's the gist of it.

    Make sense?


    "A problem well stated is a problem half solved.” - Charles F. Kettering

    Saturday, September 2, 2017 3:35 PM
  • Yes which is what I had thought I had done above in my example which causes an error

    The Public Class ExtractedEventData contains all my properties

    ???


    Darren Rose

    Saturday, September 2, 2017 3:54 PM
  • Yes which is what I had thought I had done above in my example which causes an error

    The Public Class ExtractedEventData contains all my properties

    ???


    Darren Rose

    I see that now, but I don't see where you create a NEW instance of the class.

    That's imperative.

    With a structure you don't have to but with a class it's not optional.

    ***** EDIT *****

    Copying yours and trying to modify it on the fly here:

        Private Function GetEventData(ByVal EventID As Integer)
            Dim results As ExtractedEventData = Nothing
    
            Select Case EventID
                Case 1102
                    results = New ExtractedEventData
                    results.ShortMessage = "The audit log was cleared"
                    results.SubjectUserName = "ddd"
                    results.IpAddress = "aaa"
            End Select
    
            Return results
        End Function

    You can (and I would) put those property settings in an initializer with the "With" keyword.


    "A problem well stated is a problem half solved.” - Charles F. Kettering



    • Edited by Frank L. Smith Saturday, September 2, 2017 4:09 PM ...formatted text
    • Marked as answer by wingers Wednesday, September 13, 2017 9:34 AM
    Saturday, September 2, 2017 3:57 PM
  • I always seem to miss the NEW out!

    So I modified it like below before I saw your edit - any reason to do the NEW for each case, or is it okay how I did it at top of the function?

      Public Function GetEventData(ByVal EventID As Integer)
            Dim results As New ExtractedEventData
    
            Select Case EventID
                Case 1102
                    results.ShortMessage = "The audit log was cleared"
                    results.SubjectUserName = "ddd"
                    results.IpAddress = "aaa"
                Case 4616
                    results.ShortMessage = "The system time was changed"
                    results.SubjectUserName = "eee"
                    results.IpAddress = "bbb"
            End Select
    
            Return results
        End Function

    I also changed

    Public Function GetEventData(ByVal EventID As Integer)

    to

    Public Function GetEventData(ByVal EventID As Integer) As ExtractedEventData

    So that when I then do as below and type results. it then shows me list of available properties e.g. .ShortMessage, .SubjectName etc

    Is that okay or wrong way to do it?

    Dim results = GetEventData(4616)
            MsgBox(results.ShortMessage)


    Darren Rose

    Saturday, September 2, 2017 4:14 PM
  • I always seem to miss the NEW out!

    So I modified it like below before I saw your edit - any reason to do the NEW for each case, or is it okay how I did it at top of the function?

      Public Function GetEventData(ByVal EventID As Integer)
            Dim results As New ExtractedEventData
    
            Select Case EventID
                Case 1102
                    results.ShortMessage = "The audit log was cleared"
                    results.SubjectUserName = "ddd"
                    results.IpAddress = "aaa"
                Case 4616
                    results.ShortMessage = "The system time was changed"
                    results.SubjectUserName = "eee"
                    results.IpAddress = "bbb"
            End Select
    
            Return results
        End Function

    I also changed

    Public Function GetEventData(ByVal EventID As Integer)

    to

    Public Function GetEventData(ByVal EventID As Integer) As ExtractedEventData

    So that when I then do as below and type results. it then shows me list of available properties e.g. .ShortMessage, .SubjectName etc

    Is that okay or wrong way to do it?

    Dim results = GetEventData(4616)
            MsgBox(results.ShortMessage)


    Darren Rose

    That's fine other than this: What if it's not found? You'll be returning a new instance with default settings.

    It's a matter of choice but to me, it makes more sense to initialize it to null (Nothing) and if it's not found, it returns a null reference.

    In the calling method, test that the returned value "IsNot Nothing", but it's entirely up to you.

    ***** EDIT *****

    Use a Case Else statement and in that, set the return value to Nothing.


    "A problem well stated is a problem half solved.” - Charles F. Kettering



    Saturday, September 2, 2017 4:20 PM
  • You beat me to it again.. that was what I was then going to say, I had planned to do a Case Else anyway to cover IDs not included in my list, so that will cover it

    Thanks Frank


    Darren Rose

    Saturday, September 2, 2017 4:30 PM
  • You beat me to it again.. that was what I was then going to say, I had planned to do a Case Else anyway to cover IDs not included in my list, so that will cover it

    Thanks Frank


    Darren Rose


    :-)

    "A problem well stated is a problem half solved.” - Charles F. Kettering

    Saturday, September 2, 2017 4:32 PM
  • ***** EDIT *****

    Use a Case Else statement and in that, set the return value to Nothing.


    "A problem well stated is a problem half solved.” - Charles F. Kettering



    In Case Else I have done results = Nothing but it still gives me an error about null reference for any where I haven't specifically set a value?

    System.NullReferenceException: 'Object reference not set to an instance of an object.'

    To get round it I have had to manually set them all to "" in my Function

    Public Function GetEventData(ByVal EventRecord As EventRecord) As ExtractedEventData
            Dim results As New ExtractedEventData
    
            ' initially set them all to "" so no errors
            results.ShortMessage = ""
            results.SubjectUserName = ""
            results.SubjectLogonId = ""
            results.SubjectDomainName = ""
            results.TargetUserName = ""
            results.TargetLogonId = ""
            results.LogonType = ""
            results.LogonProcessName = ""
            results.WorkstationName = ""
    
    ....
    ....
    End Function

    as even setting them to an initial value of "" in my class as below doesn't stop error?

    Public Class ExtractedEventData
            Public Property ShortMessage As String = ""
            Public Property SubjectUserName As String = ""

    any neater way of doing it?


    Darren Rose

    Saturday, September 2, 2017 7:45 PM
  • Darren,

    I don't know the context here - and I don't want to own this. ;-)

    Bear with me about an hour or so and I'll put together an example that will work on your end as well as here so we can then talk about it.


    "A problem well stated is a problem half solved.” - Charles F. Kettering


    • Edited by Frank L. Smith Saturday, September 2, 2017 7:57 PM ...typo
    Saturday, September 2, 2017 7:57 PM
  • Not my best work but it'll do in a hurry. This will work:

    Option Strict On
    Option Explicit On
    Option Infer Off
    
    Public Class Form1
        Private Sub Form1_Load(ByVal sender As System.Object, _
                               ByVal e As System.EventArgs) _
                               Handles MyBase.Load
    
            Dim pdList As New List(Of PersonData)
            Dim pd As New PersonData(pdList)
    
            Stop
    
            Dim person1 As PersonData = pd.GetPerson(pdList, "aOpdyke@blazemail.com")
    
            If person1 IsNot Nothing Then
                MessageBox.Show(String.Format("{0} {1} {2}", _
                                              person1.FirstName, _
                                              person1.MiddleInitial, _
                                              person1.LastName))
            End If
    
            Dim person2 As PersonData = pd.GetPerson(pdList, "somewhere@OverTheRainbow.net")
    
            If person2 IsNot Nothing Then
                MessageBox.Show(String.Format("{0} {1} {2}", _
                                             person2.FirstName, _
                                             person2.MiddleInitial, _
                                             person2.LastName))
            End If
    
            Stop
    
        End Sub
    End Class
    
    
    
    
    
    Public Class PersonData
        Private _firstName As String
        Private _middleInitial As String
        Private _lastName As String
        Private _streetAddress As String
        Private _city As String
        Private _state As String
        Private _zipCode As String
        Private _email As String
    
        Public Sub New(ByVal personList As List(Of PersonData))
    
            If personList IsNot Nothing Then
                With personList
                    .Clear()
                    .TrimExcess()
                End With
    
                InitializeData("http://www.fls-online.net/VBNet_Forum/SampleData/Sample_Data_100.xml", personList)
            End If
    
        End Sub
    
        Private Sub New(ByVal firstName As String, _
                        ByVal middleInitial As String, _
                        ByVal lastName As String, _
                        ByVal streetAddress As String, _
                        ByVal city As String, _
                        ByVal state As String, _
                        ByVal zipCode As String, _
                        ByVal email As String)
    
            _firstName = firstName.Trim
            _middleInitial = middleInitial.Trim
            _lastName = lastName.Trim
            _streetAddress = streetAddress.Trim
            _city = city.Trim
            _state = state.Trim
            _zipCode = zipCode.Trim
            _email = email.Trim
    
        End Sub
    
        Private Sub InitializeData(ByVal url As String, _
                                   ByVal personList As List(Of PersonData))
    
            If Not String.IsNullOrWhiteSpace(url) Then
                If personList IsNot Nothing Then
                    Dim xDoc As XElement = XElement.Load(url)
    
                    For Each info As XElement In xDoc...<Person>
                        personList.Add(New PersonData(info...<FirstName>.Value, _
                                                      info...<MiddleInitial>.Value, _
                                                      info...<LastName>.Value, _
                                                      info...<StreetAddress>.Value, _
                                                      info...<CityName>.Value, _
                                                      info...<StateName>.Value, _
                                                      info...<ZipCode>.Value, _
                                                      info...<EmailAddress>.Value))
                    Next
                End If
            End If
    
        End Sub
    
        Public Function GetPerson(ByVal people As IEnumerable(Of PersonData), _
                                  ByVal eMail As String) As PersonData
    
            Dim retVal As PersonData = Nothing
    
            If people IsNot Nothing Then
                If Not String.IsNullOrWhiteSpace(eMail) Then
                    Dim qry As System.Collections.Generic.IEnumerable(Of PersonData) = _
                        From pd As PersonData In people _
                            Where pd.Email.ToLower.Replace(" "c, "") = eMail.ToLower.Replace(" "c, "")
    
                    If qry.Count = 1 Then
                        retVal = qry.First
                    End If
                End If
            End If
    
            Return retVal
    
        End Function
    
        Public ReadOnly Property City As String
            Get
                Return _city
            End Get
        End Property
    
        Public ReadOnly Property Email As String
            Get
                Return _email
            End Get
        End Property
    
        Public ReadOnly Property FirstName As String
            Get
                Return _firstName
            End Get
        End Property
    
        Public ReadOnly Property LastName As String
            Get
                Return _lastName
            End Get
        End Property
    
        Public ReadOnly Property MiddleInitial As String
            Get
                Return _middleInitial
            End Get
        End Property
    
        Public ReadOnly Property State As String
            Get
                Return _state
            End Get
        End Property
    
        Public ReadOnly Property StreetAddress As String
            Get
                Return _streetAddress
            End Get
        End Property
    
        Public ReadOnly Property ZipCode As String
            Get
                Return _zipCode
            End Get
        End Property
    End Class

    At the first "Stop", verify that it returned 100 instances in that list. When you then continue, you'll see the MessageBox because that e-mail exists and is one of one in the data.

    When you continue it again, it will bypass the second one because that e-mail address isn't in the data.

    Make sure that your function has a return path no matter what happens in the code (which is why I use "retVal") and in the calling code, check that it's not null before you try to access anything.

    Does this help at all?


    "A problem well stated is a problem half solved.” - Charles F. Kettering

    Saturday, September 2, 2017 8:22 PM
  • Thank you Frank, will look at that in more detail tomorrow, but I think I get the idea from that as to how to get mine working better

    Darren Rose

    Saturday, September 2, 2017 8:29 PM
  • Thank you Frank, will look at that in more detail tomorrow, but I think I get the idea from that as to how to get mine working better

    Darren Rose

    Ok good.

    Getting a null reference exception means that you're trying to access something that doesn't exist:

    Dim nil As String = Nothing
    Dim trimmedValue As String = nil.Trim
    
    Stop

    You'll get it. :)


    "A problem well stated is a problem half solved.” - Charles F. Kettering


    • Edited by Frank L. Smith Saturday, September 2, 2017 8:34 PM ...typo
    Saturday, September 2, 2017 8:30 PM
  • Thank you Frank, will look at that in more detail tomorrow, but I think I get the idea from that as to how to get mine working better

    Note this error in the examples you have posted:
     Private Function GetEventData(ByVal EventID As Integer) As ExtractedEventData

    A function must be declared with a return type.

    Saturday, September 2, 2017 10:02 PM
  • Thank you Frank, will look at that in more detail tomorrow, but I think I get the idea from that as to how to get mine working better

    Note this error in the examples you have posted:
     Private Function GetEventData(ByVal EventID As Integer) As ExtractedEventData

    A function must be declared with a return type.

    It does.

    In his initial post he shows the following declaration:

        Public Class ExtractedEventData
            Public Property ShortMessage As String
            Public Property SubjectUserName As String
            Public Property IpAddress As String
        End Class

    Why is that not a valid return type?


    "A problem well stated is a problem half solved.” - Charles F. Kettering

    Saturday, September 2, 2017 10:07 PM
  • Why is that not a valid return type?

    It is a valid return type.  But it is not declared as the return type of the function.   The function will return an Object, not the type that OP is expecting.

    Saturday, September 2, 2017 10:17 PM
  • Why is that not a valid return type?

    It is a valid return type.  But it is not declared as the return type of the function.   The function will return an Object, not the type that OP is expecting.

    Show where he'd be returning an object instead of the declared return type?

    I missed it, obviously!

    *****

    If he were to return an object (via type inference), the exception would be a casting exception, not a null reference exception, so you must be seeing something that I didn't.


    "A problem well stated is a problem half solved.” - Charles F. Kettering

    Saturday, September 2, 2017 10:25 PM
  • @Acamar

    8th post down I mentioned I changed

    Public Function GetEventData(ByVal EventID As Integer)

    to

    Public Function GetEventData(ByVal EventID As Integer) As ExtractedEventData


    Darren Rose

    Saturday, September 2, 2017 10:26 PM
  • @Acamar

    8th post down I mentioned I changed

    Public Function GetEventData(ByVal EventID As Integer)

    to

    Public Function GetEventData(ByVal EventID As Integer) As ExtractedEventData


    Darren Rose

    Which is correct.

    A NullReferenceException is when you're trying to access something that logically should be there but isn't (like a member of a class when the instance is null). That's what I think is going on...


    "A problem well stated is a problem half solved.” - Charles F. Kettering

    Saturday, September 2, 2017 10:28 PM
  • @Acamar

    8th post down I mentioned I changed

    Public Function GetEventData(ByVal EventID As Integer)

    to

    Public Function GetEventData(ByVal EventID As Integer) As ExtractedEventData


    Darren Rose

    Which is correct.

    A NullReferenceException is when you're trying to access something that logically should be there but isn't (like a member of a class when the instance is null). That's what I think is going on...


    "A problem well stated is a problem half solved.” - Charles F. Kettering


    exactly - and thanks to your help it is now working fine :)

    Darren Rose

    Saturday, September 2, 2017 10:30 PM
  • exactly - and thanks to your help it is now working fine :)

    Darren Rose

    Good then. :)

    "A problem well stated is a problem half solved.” - Charles F. Kettering

    Saturday, September 2, 2017 10:33 PM
  • Public Function GetEventData(ByVal EventID As Integer)

    to

    Public Function GetEventData(ByVal EventID As Integer) As ExtractedEventData

    Yes. The reference in my post was to the original code. Your solution needed both changes to make it work - give the function a return value and instantiate the object.

    Saturday, September 2, 2017 11:04 PM
  • Hi wingers,

    It seems that you have solve your issue now, please remember to close your thread by marking the helpful post as answer, it is beneficial to other community members who face the same issue.

    Thanks for your understanding.

    Best Regards,

    Cherry


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    Wednesday, September 13, 2017 9:10 AM
    Moderator