Reputation: 1274
I just stumbled upon a problem which took me hours to find the reason for.
I declared a class variable as ReadOnly
because I wanted to set its value in the constructor of the class (all following code is example code, so it probably doesn't make much sense).
Private ReadOnly _content as String
Public Sub New(content As String)
_content = content
End Sub
Public ReadOnly Property Content As String
Get
Return _content
End Get
End Property
After a little bit of coding, I figured out that I wanted to do other stuff depending on the value of this variable, so I changed my code to:
Private ReadOnly _content as String
Public Sub New(content As String)
Me.Content = content
End Sub
Public Property Content As String
Get
Return _content
End Get
Private Set(value As String)
If Me.SetValue(Of String)(_content, value) AndAlso (_content = "foo") Then
'other stuff
End If
End Set
End Property
Private Function SetValue(Of T)(ByRef storage As T, value As T) As Boolean
storage = value
Return True
End Sub
But this changed code didn't work, the variable _content
never got the value I passed in the constructor. Visual Studio 2019 showed no error and the code compiled and ran.
After a lot of trial and error I found out, that I forgot to remove the ReadOnly
in the variable declaration, and that was the reason for my problem.
But why doesn't Visual Studio warn me about this situation, or why doesn't the program crash, when I try to set a ReadOnly
variable outside of the constructor? What is this ReadOnly
in the variable declaration good for, when it can only cause confusion and hard to find errors?
Upvotes: 3
Views: 882
Reputation: 111940
This question was asked even on the github of roslyn and of vblang. There was a definite answer:
Page 130 of the Visual Basic Language Specification states: Copy-in copy-back. If the type of the variable being passed to a reference parameter is not compatible with the reference parameter's type, or if a non-variable (e.g. a property) is passed as an argument to a reference parameter, or if the invocation is late-bound, then a temporary variable is allocated and passed to the reference parameter. The value being passed in will be copied into this temporary variable before the method is invoked and will be copied back to the original variable (if there is one and if it's writable) when the method returns.
There was even an historical justification:
This is by design. In VB6 ByRef was the default so passing any argument would have been ByRef, ReadOnly properties included.
If you are curious, I've created a SharpLab example with a simplified version of your code (I've removed anything that wasn't central to your problem and put another non-ReadOnly
field for comparison) where you can observe what is happening. The C# code generated is equivalent to the IL code generated (you can try changing the Results language combo box to IL but it is much more unreadable unless you dabble in IL code programming).
Upvotes: 7
Reputation: 177
It ensures the field can only be set from the constructor or in it's declaration. If you for example have multiple constructors, they can set a different value for the read-only field, after that it cannot be modified anymore. This is different from using a constant value that can not change.
Upvotes: -1