The concept of a "default property" for an object isn't what it used to be. Programmers new to VB.NET after 2001 (When VB6 was taken behind the barn and shot.) may not even be aware of how it used to be. In brief, you used to be able to write code like this:
TextBox1 = "Text"
This was really shorthand for ...
TextBox1.Text = "Text"
... because the Text property was the default property.
VB.NET continues to include a "Default" property attribute, but it's not at all the same. In fact, the way it's really used is documented in such an obscure way at Microsoft that there is a real need for some clarification.
The Microsoft documentation for declaring a Default Property in a Class definition is fairly straightforward. But you have to read the whole thing. The initial step-by-step instructions don't work. You could get the idea that all you have to do is simply use the Default keyword instead of Private, Public, or Shared.
Default Property myProperty(ByVal index As Integer) As String
There are a few more rules.
- The new VB 2010 "auto implemented" property syntax doesn't work. In other words, you also need a Get and Set and an End Property. (But, Microsoft doesn't make this part of their documentation.)
- You have to use at least one parameter for the property. (There's more to this rule, too.)
You might think that you can just write this code:
' Code in a calling procedure Dim theInstance As New aClassExample MsgBox(theInstance) Public Class aClassExample Private m_myProperty As String = "Red" Default Property myProperty( ByVal theDefaultArg As Integer ) As String Get myProperty = m_myProperty End Get Set(ByVal value As String) m_myProperty = value End Set End Property End Class
No. An ArgumentException is thrown. It's fairly obvious to see that an argument must be passed, but the language of the exception message is curious:
In order to evaluate an indexed property, the property must be qualified and the arguments must be explicitly supplied by the user.
So, this isn't just a default property, it's also an indexed property. That's something that the documentation doesn't make clear. The code that does work simply adds the parameter to the instance in the calling procedure:
What does the "1" parameter do in this code? Absolutely nothing. But it still has to be there. In other words, there is no way to write a default property that is not indexed.
The right way to think of a "default" property in VB.NET is to substitute the word "indexed" for "default". In VB.NET, you can create a property that makes it simpler to define indexes to a collection. Microsoft just used the keyword "Default" for this type of property. Many sources, in fact, refer to a VB.NET default property as an indexer because that's what it does.
Here's an example that does it right. This code declares an indexer in the class DefaultPropClass. This indexer is capable of returning a member of an array that is maintained in an instance of the class by either an index number or a string that matches an element of the array.
Public Class DefaultPropClass Private m_theProperty As List(Of theStructure) Public Sub New() m_theProperty = New List(Of theStructure) End Sub ' This ReadOnly Property returns the ' value corresponding to an integer index Default Property theProperty( ByVal index As Integer) As theStructure Get Return m_theProperty(index) End Get Set(ByVal value As theStructure) m_theProperty.Add(value) End Set End Property ' This ReadOnly Property returns the ' value corresponding to a string key Default ReadOnly Property theProperty( ByVal index As String) As theStructure Get For Each p As theStructure In m_theProperty If p.theKey = index Then Return p End If Next Return Nothing End Get End Property End Class Public Structure theStructure Dim theKey As String Dim theValue As String End Structure
The code that uses this class might look like this:
Dim aCollection As New theStructure aCollection.theKey = "1" aCollection.theValue = "George" Dim aInstance As New DefaultPropClass aInstance(1) = aCollection aCollection.theKey = "2" aCollection.theValue = "Jeremy" aInstance(2) = aCollection MsgBox("Integer parameter 1: " & aInstance(1).theValue) MsgBox("String parameter 1: " & aInstance("1").theValue)
The value returned by the integer parameter 1 is "Jeremy" since the collection is zero based. the value returned by the string parameter "1" is "George". You might be asking, "Where is anything defaulted?" One way to answer the question is to note that this code also works:
MsgBox("String parameter 1: " & aInstance.theProperty("1").theValue)
In other words, by using a default property you can avoid typing the text ".theProperty" in your code. It doesn't seem worth it. This might help explain why Microsoft has made upgrading their documentation on this a (a-hem) secondary priority. In fact, at the very end of one Microsoft page, they're pretty blunt about it:
You should consider not defining default properties. For code readability, you should also consider always referring to all properties explicitly, even default properties.