Is ByRef vs ByVal generating errors?

ByRef

vs ByVal

generates errors !?

I had a method that used Object

Function Foo(ByRef bar as CustomObject) as Boolean

      

this method generated errors as some strange .NET Runtime things changed the object bar

by calling Dispose () al.

Lots of time spent figuring out the thing (where the object changes ...) until someone replaced ByRef

with ByVal

and the object changed when going to this method ...

Can anyone explain this what's going on?

Nota Bene (change)

As in my case, Foo

does the function do NOT modifybar

, should it ByRef

or ByVal

have the same effect ?

Foo

just read Properties from bar

.

The code:

Module Module1

  Sub Main()
    Dim b As New Bar
    ' see the output bellow '
    Foo(b.Name)
    Console.ReadLine()
  End Sub

  Function Foo(ByRef name As String) As Boolean
    Console.WriteLine("Name is : '{0}'", name)
  End Function

  Class Bar
    Private _Name As String = "John"

    Property Name()
      Get
        Return _Name
      End Get
      Set(ByVal value)
        If _Name IsNot Nothing Then
          '_Name.Dispose() If this were an IDisposable, would have problems here'
        End If
        Console.WriteLine("Name is Changed to '{0}'", value)
      End Set
    End Property
  End Class

End Module

      

Output:

Name: "John"
Name changed to "John"

+2


a source to share


4 answers


In VB.NET, passing a property by reference updates the actual property, not the underlying value. Thus, when Foo exits, the CLR calls the Property Set method to update the property value with any new value at the end of the function (even if it hasn't changed).

This behavior is described in the VB.NET Language Specification (reference parameters, last 3 paragraphs):



http://msdn.microsoft.com/en-us/library/aa711958(v=VS.71).aspx

+4


a source


Passing an argument ByRef

means that if someone assigns a new value to a variable, that new value will be passed back to the calling function. Passing ByVal

passes a copy of this value to the function, so changes are not passed back to the caller.

Note that when I refer to the value, this is what is actually stored in this variable. With reference types, this means it is a reference. Passing a reference type by value does not copy the entire instance, it just copies the reference . This means that any changes made to the object itself will still be visible to the calling function.

For example, consider this class:

Public Class Foo
    Private m_Value as string

    Public Property Value as String
        Get
            return m_Value
        End Get
        Set(Value as String)
            m_Value = Value
        End Set
    End Property
End Class

      

And in our program we have two functions:

Public Sub DoWork(ByVal obj as Foo)
    obj = Nothing
End Sub

Public Sub DoWorkRef(ByRef obj as Foo)
    obj = Nothing
End Sub

      

And we call them like this:

Dim obj1 as new Foo()
Dim obj2 as new Foo()

obj1.Value = "bar"
obj2.Value = "baz"

DoWork(obj1)
DoWorkRef(obj2)

      

At the end, this function obj1

will still matter, but obj2

will Nothing

. This is due to the fact that it obj1

is passed by value, so the code in DoWork

works on a copy of that variable (again, this is the same instance, it is just a variable that is different), whereas it obj2

is passed by reference, so it points to the same variable as and the main code.



To indicate "the same instance", let's say we changed the functions as follows:

Public Sub DoWork(ByVal obj as Foo)
    obj.Value = "beep"
End Sub

Public Sub DoWorkRef(ByRef obj as Foo)
    obj.Value = "bop"
End Sub

      

If we were to run the same code again, we would end up with obj1.Value

equal "beep" and obj2.Value

equal "bop". This is because although we are passing obj1

by value, this value is a reference. You now have two variables pointing to the same instance, so whatever is done will make that instance reflected in both variables.

It's important to remember that the only effective difference between ByRef

and ByVal

occurs when you assign a new value to the variable itself
. All other actions are virtually the same.

Editing after reply

You are not passing a variable as a parameter ByRef

: you are passing a property. While C # will not allow this (due to this very problem), VB.NET will. If you pass the property as a parameter ByRef

, essentially how to do it:

Dim _temp as String = b.Name
Foo(_temp)
b.Name = _temp

      

In other words, when a property is passed as a parameter ByRef

, the setter for that property is always invoked using the value present in the variable after the function is executed, even if the value has not changed.

It's a good rule of thumb not to pass properties as parameters ByRef

.

+6


a source


Well yes, if you change from parameter declaration ByRef

to ByVal

, it changes the behavior that breaks your code. This is one of the reasons why, in C #, it must also be specified in the calling code.

If there was no difference between ByRef

and ByVal

, we would not have become both of them.

I have an article on parameter passing that can help you understand the difference between the two; it is written in C # but the basic principles are the same.

+1


a source


Two things stood out to me:

this method generated errors because some strange .NET Runtime thing changed the bar object by calling Dispose () al.

and

someone replaced ByRef ByVal and the object hasn't changed anymore

Remember that variables for reference types in .Net work the same way as pointers, since a variable is just a kind of handle to an actual object in memory. When you pass this object to the ByVal function (the default in .Net, and you shouldn't change from the default unless you know the implications), you're making a copy of the handle or reference. When you pass a ByRef object, you are passing the reference yourself.

This means that if you have to do something like assigning a reference to another object to your bar variable in that function, you also changed the original variable outside the function. Even though your function never changed the object, by doing this assignment, you also changed the object reference outside the function, and thus probably lost that confirmation - hence the object was deleted.

0


a source







All Articles