none
SetValue() passes the object by value ?? RRS feed

  • Question

  • The SetValue() function is defined as follows (from the Object Browser)

    Public Sub SetValue(ByVal obj As Object, ByVal value As Object)

    And claims to do the following 

    "Sets the value of the field supported by the given object."

    But note that the object is passed by value, and thus by definition, cannot be changed.  Is this a bug?  A similar problem exists for Class Properties.

    Thus this code works (for two example FieldNames):

        Public Sub SetFieldValue(ByRef obj As Object, ByVal FieldName As String, ByRef val As Object)
            Select Case FieldName 
                Case "name"
                    obj.name = val
                Case "location"
                    obj.location = val
        End Sub

    But this one does not work (but throws no errors):

        Public Sub SetFieldValue(ByRef obj As Object, ByVal FieldName As String, ByRef val As Object)
            Dim objType As Type = obj.GetType()
            Dim pInfo As System.Reflection.FieldInfo = objType.GetField(FieldName)
            pInfo.SetValue(obj, val)
        End Sub

    I have potentially hundreds of allowed field names, so I would rather not create a huge Select Case solution.

    Mike


    Monday, January 14, 2013 9:41 PM

Answers

  • No, that definition doesn't mean that the object can't be changed.  What is being passed by value is the reference (pointer) to the object, not the object itself.  So if the SetValue method is called like this

    SetValue(myObject, 3)


    The SetValue method's argument "obj" will contain a copy of the pointer to myObject and so when it modifies obj, it will also be modifying myObject. But if SetValue includes the following statement:

    obj = New TextBox


    obj will now point to a new object (the TextBox) but myObject is not changed.

    This is different from what could happen if obj is passed by reference. In that case, if obj is changed to point to a new object, myObject will also point to that new object.

    Here is an example.  Let's assume we have a form that includes a button and two TextBoxes:

    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        Dim myCtl As Control = Me.TextBox1
        ChangeText(myCtl, "Update")
        MessageBox.Show(myCtl.Name)
    End Sub
    
    Private Sub ChangeText(ByVal ctl As Control, ByVal text As String)
        ctl = Me.TextBox2
        ctl.Text = text
    End Sub

    With the code above, when Button1 is clicked, TextBox2 will display "Update" and the MessageBox will display "TextBox1".  Now if you change the first argument of ChangeText so that it is passed ByRef and run the application again, TextBox2 will still display "Update", but the MessageBox will display "TextBox2".

    • Edited by Blackwood Monday, January 14, 2013 10:24 PM add example
    • Marked as answer by Michael at SAI Tuesday, January 15, 2013 6:59 AM
    Monday, January 14, 2013 10:10 PM

All replies

  • No, that definition doesn't mean that the object can't be changed.  What is being passed by value is the reference (pointer) to the object, not the object itself.  So if the SetValue method is called like this

    SetValue(myObject, 3)


    The SetValue method's argument "obj" will contain a copy of the pointer to myObject and so when it modifies obj, it will also be modifying myObject. But if SetValue includes the following statement:

    obj = New TextBox


    obj will now point to a new object (the TextBox) but myObject is not changed.

    This is different from what could happen if obj is passed by reference. In that case, if obj is changed to point to a new object, myObject will also point to that new object.

    Here is an example.  Let's assume we have a form that includes a button and two TextBoxes:

    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        Dim myCtl As Control = Me.TextBox1
        ChangeText(myCtl, "Update")
        MessageBox.Show(myCtl.Name)
    End Sub
    
    Private Sub ChangeText(ByVal ctl As Control, ByVal text As String)
        ctl = Me.TextBox2
        ctl.Text = text
    End Sub

    With the code above, when Button1 is clicked, TextBox2 will display "Update" and the MessageBox will display "TextBox1".  Now if you change the first argument of ChangeText so that it is passed ByRef and run the application again, TextBox2 will still display "Update", but the MessageBox will display "TextBox2".

    • Edited by Blackwood Monday, January 14, 2013 10:24 PM add example
    • Marked as answer by Michael at SAI Tuesday, January 15, 2013 6:59 AM
    Monday, January 14, 2013 10:10 PM
  • OK, that helps thank you Blackwood.  In my defence, the MS manual says " Passing an argument by value means the procedure cannot modify the contents of the variable element in the calling code underlying the argument. " 

    My real problem is with regard to System.Reflection.FieldInfo.SetValue, which runs happily, throws no errors, and does nothing.  My code above shows what I am trying to do.

    Mike

     
    Monday, January 14, 2013 10:21 PM