VB.Net Gotcha using ByRef

C# will not let you compile if you try an pass a property or a readonly field as a ref argument to a method:

you will get:

A readonly field cannot be passed ref or out (except in a constructor)


A property or indexer may not be passed as an out or ref parameter

This is good it protects from doing something silly, however VB.NET does not have this compile checking and instead will let the following compile without even a warning:

Public Class AnotherTestClass
    Private _number As Integer

    Public ReadOnly Property Number() As Integer
            Return _number
        End Get
    End Property

    Public Sub ChangeMyNumber()
    End Sub

End Class

When the ChangeNumber method on the TestClass uses byref for the integer passed in:

Public Shared Sub ChangeNumber(byRef output)
    output = 1
End Sub

When the above is executed the Number property remains the same as before the method call. This was tested in VS2005, at first i thought it was a VS2003 only issue.

3 thoughts on “VB.Net Gotcha using ByRef

  1. Interesting issue I’ve found with VB.NET that if you pass an object ByVal to a method say like a bitmap and you make any change to the object in the method then the original object is changed as well.

    I had always thought that with ByRef this would happen but not with ByVal. I’m not sure if this happens in C# or not though.

  2. Yeah reference types get treated differently, when passing an object a pointer to that object gets passed by default (ByVal) which allows modifications limited to the publicly declared fields/properties/methods, however if you pass an object ByRef it actually passes a pointer to the pointer meaning that the method can now totally replace the object that was passed in with its’s own version, this is bad in most cases i.e.

    public sub Test1(ByVal o as MyObject)
    // limited access to MyObject
    o.MyProperty = “test”

    // caller not affected
    o = new MyObject()
    end sub

    public sub Test2(ByRef o as MyObject)
    // limited access to MyObject as before
    o.MyProperty = “test”

    // caller affected encapsulation broken
    o = new MyObject()
    end sub

  3. Ah that is much more clear to me.

    When I programmed with VB6 I don’t think it worked this way so I was surprised that it worked in VB.NET. With this revelation now it makes more sense.

    Thanks for the info.

Comments are closed.