I've noticed some seemingly weird issues in Visual Studio 2008 (.NET 3.5) and also in Visual Studio 2010 Beta 2 (.NET 4.0). These issues may have existed in prior versions as well. Maybe they are not an issue, but either way, I would like to see if there is are logical explanations for these before I submit a report on Microsoft Connect.
The Setup (in VB, C# results differ and are included later in the post):
Public Class SomeClass
Public Property SomeProperty() As String
Get
Return String.Empty
End Get
Set(ByVal value As String)
End Set
End Property
End Class
Public Class SomeOtherClass
Public Sub New()
Dim sc As New SomeClass()
Me.SomeFunction(sc.SomeProperty)
End Sub
''' <summary>The param as Object fn()</summary> '''
Public Sub SomeFunction(ByVal param As Object)
End Sub
''' <summary>The param as T fn()</summary> '''
Public Sub SomeFunction(Of T)(ByRef param As T)
End Sub
End Class
In this sutation, the Me.SomeFunction(sc.SomeProperty)
call, from the point of view of IntelliSense, looks like this:
and, not surprisingly, this is also what is called at runtime.
So, I guess the first question I have is, why was the ByRef templated overload version of the function chosen over the ByVal Object overload version of the function? My guess is that the compiler and IntelliSense simply favor the templated versions over non-templated versions. At runtime, it is in fact the ByRef templated version of the function that is called. (This is not the defect, this is simply a personal want-to-know question.)
Now, make a slight change to the SomeProperty
property such that the setter is now private:
Public Property SomeProperty() As String
Get
Return String.Empty
End Get
Private Set(ByVal value As String)
End Set
End Property
As soon as you do this, the following happens to the Me.SomeFunction(sc.SomeProperty)
line:
In this case, IntelliSense is suggesting that the ByVal Object overload version of the function is being called, however the error message is the 'Set' accessor of property 'SomeProperty' is not accessible
indicating that the compiler is still expecting to call the ByRef templated version. So, this is my second question. Why is Intellisense claiming one thing while the VB compiler is clearly trying something else? This seems broken to me. Or am I missing something?
If instead of having a private setter on SomeProperty
but instead the property was simply marked ReadOnly and the setter part removed, then the ByRef templated version of the function is shown in IntelliSense and is called at runtime (with no runtime errors). So this leads me to my third question, why is the VB compiler treating the input to ByRef params different for properties that are ReadOnly vs not-ReadOnly, but have an out-of-scope setter in VB As far as SomeFunction(Of T)(...) is concerned, in its current scope, that property should be as if it were ReadOnly and I would expect it to be callable just as if the property was in fact ReadOnly. But instead it produces a build error.
In correlation with question three, doing the exact same setup (with the Private setter), C# has the result I was expecting.
Here, you can see IntelliSense is claiming that the SomeFunction(Object) overload of the function is being called and there is no build error. At runtime the SomeFunction(Object) version is in fact called. So, why isn't the same SomeFunction(Object) version being called in the VB.NET situation? Why does VB.NET still think the SomeFunction(Of T)(ByRef T) version need to be called? It looks like IntelliSense is nailing it correctly in both C# and VB.NET, the C# compiler is doing the right thing, but the VB.NET compiler is still convinced that it should be calling the ByRef templated version. To me it seems that the C# compiler is picking one overload, while the VB.NET compiler is picking a different overload, in the exact same situation. Am I wrong?