Okay, so I stumbled upon an auto generated private member I wasn't aware of.
I know that if you have a property named e.g. P then the name get_P is reserved for the getter method and the name set_P is reserved for the setter method.
But what I didn't know was that the name _P is also reserved. It seems that this only applies to properties (not ReadOnly / WriteOnly) and fields defiend as WithEvents.
Public Class Test
Public Property p As Object
Public WriteOnly Property pW() As Object
Set(value As Object)
End Set
End Property
Public ReadOnly Property pR() As Object
Get
End Get
End Property
Public f As Object
Public WithEvents fWE As Object
Private _p As Object
Private _pW As Object
Private _pR As Object
Private _f As Object
Private _fWE As Object
End Class
The above class will produce the following errors:
1) property 'p' implicitly defines '_p', which conflicts with a member of the same name in class 'Test'.
2) WithEvents variable 'fWE' implicitly defines '_fWE', which conflicts with a member of the same name in class 'Test'.
If I remove all the fields named _{name} and return all members (including NonPublic fields) of type Test one can clearly see the auto generated members.
.cctor (Constructor)
.ctor (Constructor)
__ENCAddToList (Method)
__ENCList (Field)
_fWE (Field) <------------------------------- *2
_p (Field) <---------------------------------- *1
Equals (Method)
f (Field)
Finalize (Method)
fWE (Property)
get_fWE (Method)
get_p (Method)
get_pR (Method)
GetHashCode (Method)
GetType (Method)
MemberwiseClone (Method)
p (Property)
pR (Property)
pW (Property)
set_fWE (Method)
set_p (Method)
set_pW (Method)
ToString (Method)
So does anybody know why these fields are generated and/or their purpose?
It's because you're using auto generated properties. Those fields are automatically generated as the backing fields for the property. See section 9.7.4 of the VB 10 Lanugage Spec:
9.7.4 Automatically Implemented Properties
If a property omits declaration of any accessors, an implementation of the
property will be automatically supplied unless the property is declared in
an interface or is declared MustOverride. Only read/write properties with no
arguments can be automatically implemented; otherwise, a compile-time error
occurs.
An automatically implemented property x, even one overriding another
property, introduces a private local variable _x with the same type as the
property. If there is a collision between the local variable's name and
another declaration, a compile-time error will be reported.
The
automatically implemented property’s Get accessor returns the value of the
local and the property’s Set accessor that sets the value of the local.
For example, the declaration:
Public Property x() As Integer
is roughly equivalent to:
Private _x As Integer
Public Property x() As Integer
Get
Return _x
End Get
Set (value As Integer)
_x = value
End Set
End Property
Related
Suppose I have the following class:
Public Class lbMenu
Inherits Form
...
Public Sub AddItem(header As String)
Dim item As New lbMenuItem()
item.Owner = Me
item.Header = header
Controls.Add(item)
End Sub
...
End Class
and also the following class:
Public Class lbMenuItem
Inherits Control
Private _Owner As lbMenu
Public Property Owner As lbMenu
Get
Return _Owner
End Get
Set(value As lbMenu)
_Owner = value
End Set
End Property
Private _Header As String
Public Property Header As String
Get
Return _Header
End Get
Set(value As String)
_Header = value
End Set
End Property
...
End Class
As you can see, I access the Owner property of lbMenuItem from the class lbMenu.
What I want is that nobody else can access the Owner property, or maybe just to read the value of the property. I think there is no way to do that but maybe there is a solution to reach a similar situation.
Any suggestions?
Edit:
I already considered passing the owner as a parameter in the constructor, but I want that anyone can access the lbMenuItem class. Anyone can create a new instance of the class, read and write many properties, etc. The only thing I don't want is that someone can write the Owner property. Someone can create a new instance of the class without having to pass an ownerMenu parameter to the New method (he can't know what ownerMenu is for). For the same reason, lbMenuItem can't be a nested class of lbMenu.
I'm trying to get the same result as with ContextMenuStrip and ToolStripMenuItem. ToolStripMenuItem has an Owner property (which in this case has read/write access) and an OwnerItem which is read-only.
So, is there a way to make the Owner property read-only but writable from the lbMenu class?
You could just have the Owner property private or read-only if you want to allow reading its value and set it in the constructor.
Edit:
Someone can create a new instance of the class without having to pass
an ownerMenu parameter to the New method
Well, you can have two constructors, one that accepts a lbMenu parameter, and one without. So, your code would look something like this:
Public Class lbMenu
Public Sub AddItem(header As String)
Dim item As New lbMenuItem(Me)
item.Header = header
Controls.Add(item)
End Sub
End Class
Public Class lbMenuItem
' Use this instead if you don't want the property to be accessible at all.
'Private Property Owner As lbMenu
Public ReadOnly Property Owner As lbMenu
Public Property Header As String
' Allow creating an instance of the class without having to pass/set the owner.
Public Sub New()
End Sub
Public Sub New(ownerMenu As lbMenu)
Owner = ownerMenu
End Sub
End Class
One last recommendation:
Based on the names of your classes, you might consider having a parent/child relationship between them (i.e., the lbMenuItem class would be a nested class within lbMenu). This will give you the advantage of being able to access the private members of lbMenu from a lbMenuItem instance.
Hope that helps.
Addressing the new points in your edit:
ToolStripMenuItem has an Owner property ... and an OwnerItem which is read-only.
That's exactly what I proposed (i.e., to use a read-only property). Note that the OwnerItem property isn't exposed as writable to any other class.
So, is there a way to make the Owner property read-only but writable
from the lbMenu class?
No, that's not possible. A read-only property is read-only, period. You can't expose its setter to a specific class. You can, however, limit the accessibility to its setter by using the keywords Friend, Private, or Protected:
Friend Set --> will make the setter accessible (make the property writable) inside the current project and read-only outside the project.
Private Set --> will make the setter accessible from the child classes.
Protected Set --> will make the setter accessible from the derived classes.
Take a look at this question to get a better idea on how to limit the accessibility of a property setter. It's about C#, but the concept is the same.
In my VB.Net code, I know that when I declare a property in a class I can do so using the shorthand of, for example, Public Property Prop1 As String and .Net automatically creates a private variable _Prop1 that I can refer to within my class.
I also know that I can refer to that variable within my code using either _Prop1 or by Prop1.
Now since I've always assumed that the preferred method is to use the private variable, I've always tried to make modifications / write code within my class referring to _Prop1. This is where my problem now comes in...
I have the following situation:
Public Class MyClass_Base
Public Overridable Property Prop1 As String = "val1"
Public Sub Test()
If _Prop1 = ....
End Sub
End Class
Public Class MyClass
Inherits MyClass_Base
Public Overrides Property Prop1 As String = "val2"
End Class
Basically, I define the property as Overridable in my base class, now when I get to the Test() subroutine, _Prop1 has the value of Nothing. However Prop1 has the correct value of val2.
Programming gurus out there, what is the correct way to deal with this situation?
Do I ignore the auto-created prive variable _Prop1 and work with the public Prop1 or is there something else I should add in / not even use the shorthand notation for this and write my own getter / setter logic to ensure things change as I would like?
Thanks!!!
I think you've answered your own question. You should absolutely not rely on hidden compiler mechanics in your own code. You're referencing a variable that you did not declare and there is no guarantee in the framework that this variable will be there (or work as you might expect, as you've discovered) - it's a hack to use it, so don't.
Unless you have a very good reason not to, code in the class should reference the public property just the same as code using the class would. If you're using automatic properties then there is no difference between doing that and using the private variable. It also has the benefit that if you do, at a later time, decide to implement explicit getters and setters that your code does not break and that your new getters and setters get called.
To explore the reason you get the unexpected result, in declaring
Public Overrides Property Prop1 As String = "val2"
You end up with two different _Prop1 variables - MyClass_Base._Prop1 and MyClass._Prop1. When you then call Test(), you are calling the base class method and that will refer to the base class's _Prop1 variable which has not been set to anything since you have overriden the implicit variable, getter, and setter in the subclass.
To illustrate the point, this is similar to :
Public Class MyClass_Base
Private _Prop1 As String = "val1"
Public Sub Test()
Console.WriteLine(_Prop1)
End Sub
End Class
Public Class MySubClass
Inherits MyClass_Base
Private _Prop1 As String = "val2"
End Class
Sub Main()
Dim class1 As New MyClass_Base
Dim class2 As New MySubClass
class1.Test()
class2.Test()
End Sub
Where your output will be :
val1
val1
In the above case MyClass_Base._Prop1 is always initialized, however, while in your case, it is not. In either case, the Test() method belongs to the base class so it will always refer to its own _Prop1 and not any variables of the same name declared in subclasses.
If you do need to refer to the private field, for whatever reason, you have to be very careful about how you do it (and the implications that follow). Any method that does so would need to itself be Overridable if subclasses are intended to work with their own private variables in the same way. Not to suggest that you should continue to use implicit variables, but to demonstrate :
Public Class MyClass_Base
Public Overridable Property Prop1 As String = "val1"
Public Overridable Sub Test()
Console.WriteLine(_Prop1)
End Sub
End Class
Public Class MySubClass
Inherits MyClass_Base
Public Overrides Property Prop1 As String = "val2"
Public Overrides Sub Test()
Console.WriteLine(_Prop1)
End Sub
End Class
Here we get the "expected" result because MySubClass overrides test to reference its own private field. Better to just stick to using the property names.
From the documentation on Auto Implemented Properties:
"Attributes specified for the property do not apply to the backing field."
This is one of those areas where C# and VB.NET need to be aligned.
C# (correctly) does not allow you to access the auto implemented property backing field (without some convoluted work). I honestly don't know what you can access this in VB.
So the rule here is even though you can access the backing field of an auto implemented property you really shouldn't modify this directly (nor should you need to)
If you need to then you should use a defined backing field (with initialisation) and explicit Get and Set
I have a base class and a child class and they both have the same property and I don't understand why VB wants me to use "Overloads" for the property in the child class. The difference is the child class version of the property is Shared while the parent class is basically there for structure. The properties look like this:
Public MustInherit Class Parent
Public ReadOnly Property Species As String
Get
Return "Should get species from a child."
End Get
End Property
End Class
Public Class Child
Inherits Parent
Public Shared ReadOnly Property Species As String
Get
Return "Species1"
End Get
End Property
End Class
Species is flagged in the line Public Shared ReadOnly Property Species As String in the child class with the warning message
property 'Species' shadows an overloadable member declared in the base
class 'Parent'. If you want to overload the base method, this method
must be declared 'Overloads'.
What I want to know is why does it want this to be overloaded? Overloading is typically used when different parameters are being passed into functions with the same name which is well documented, but I've found nothing explaining why overloads is suddenly suggested in a situation like this.
Note: that the code properly reports "Species1" regardless of if have the "Overloads" or not adding to my confusion of what it actually does...
If you want to overload the base method, this method must be declared 'Overloads'.
The error message is too generic. Note how it talks about a method even though the warning is about a property. You cannot overload a property.
If I were the King of France, I would have written the error message like:
Property 'Species' hides the 'Species' property inherited from the 'Parent' base class. Use the Shadows keyword to suppress this warning if hiding was intended. Change the name of the property if hiding was not intended.
This warning should almost never be ignored because is almost always identifies a code smell. Using the Shared keyword for Child.Species is very strange and almost certainly not what you intended. Any code that uses your Child object through a reference of type Parent will always get the wrong species name since it will use the base property. The more sane thing to do here is to declare the Parent.Species property Overridable and use the Overrides keyword in Child.Species property declaration, without Shared.
If you shadow a member - the base class will still use it's version of the member when called. For example, if a function in your base class called Species it would still get the value "Should get species from a child."
In this case, overloading will cause functions in the base class to use the child's value.
To make this a bit clearer... the following code's message box says "Original Value", not "New Value"
Public Class Form1
Dim X As New Child
Dim Y = MsgBox(X.ShowMe)
End Class
Public Class Parent
Public Function ShowMe() As String
Return member
End Function
Public Property member As String = "Original value"
End Class
Public Class Child
Inherits Parent
Public Property member As String = "New value"
End Class
I'm trying to use the DefaultValue attribute to decorate a property in order to assert the value is defaulted as a new list of a typed object in the program. The failing code is as follows:
<DataContract()>
Partial Public Class MessageBaseResponse
#Region "Properties"
<DataMember()>
Public Property Header As Header
<DataMember()>
<DefaultValue(GetType(List(Of [Error])))>
Public Property Errors As List(Of [Error])
<DataMember()>
<DefaultValue(GetType(List(Of Warning)))>
Public Property Warnings As List(Of Warning)
#End Region
End Class
How to instantiate new lists as default property value using the DefaultValue attribute approach?
The DefaultValue attribute has more to do with serializing the data, not setting the actual default value of the property. The linked page notes:
A DefaultValueAttribute will not cause a member to be automatically initialized with the attribute's value. You must set the initial value in your code.
Try instantiating the lists with the "New" keyword:
Public Property Errors As New List(Of [Error])
I have an interface IDigitalState defined as
Public Interface IDigitalState
ReadOnly Property Code As Integer
ReadOnly Property Name As String
End Interface
and a structure that implements this interface
Public Structure DigitalState
Implements IDigitalState
Private ReadOnly mCode As Integer
Private ReadOnly mName As String
Public ReadOnly Property Code As Integer Implements IDigitalState.Code
Get
Return mCode
End Get
End Property
Public ReadOnly Property Name As String Implements IDigitalState.Name
Get
Return mName
End Get
End Property
Public Sub New(ByVal code As Integer, name As String)
mCode = code
mName = name
End Sub
End Structure
What I wanted to do was declare a variable as a nullable type of IDigitalState. I understand why I cant do this because the interface may be implemented by a class which is not allowed to be nullable. Is there a way to define the interface so that it can only be implemented by a structure. I'm doubting it's possible but thought it would be worth looking into.
You can do this in combination with generics. For instance:
Sub Test(Of T As {IDigitalState, Structure})()
Dim something As T? = GetEitherValueOrNull …
End Sub
The key here is that you operate on a concrete (generic) type T which has two conditions:
it is a structure, and
it implements IDigitalState.
Or you can just use a normal variable of interface type, which can be Nothing, without the need for a Nullable.
No, there is no way.
However, you can type.
Dim nullableIDigitalState As IDigitalState = nothing
which would be declaring a variable of type IDigitalState as null. If you are talking about the Nullable<> generic that has a where constraint that limits to value types so it would only accept a structure variant of IDigitalState.
Am I missing your point?
The only situations in which it would be meaningful to restrict interface implementations to structure types are those in which the interface type is going to be used as a generic constraint, and never as a storage location type. In such situations, any code which requires type parameter to be a struct that implements the interface can specify that. Nothing would prevent classes from implementing the interface, but so what? A variable of type IDigitalState could hold a reference to a class that implements that interface, but could not be passed as a generic parameter of type T As {Structure,IDigitalState}, so code which requires a structure-type implementation wouldn't care that such things might exist.
Note, btw, that storing a struct that implements IDigitalState into a variable of type IDigitalState will effectively create a new class object with fields matching those of the structure, and store a reference to that object. If you wish to ensure that a struct which implements an interface, will behave like a struct rather than a class, you need to pass or hold it in a variable with an interface-constrained generic type, rather than in a variable of the interface type.