NOTE: This is not a duplicate of VB.NET equivalent of C# property shorthand?. This question is about how to have different access rights on getter and setter of a VB auto-property; e.g public getter and private setter. That question is about the syntax for auto-property (and does not mention this issue).
I am trying to convert an auto Property (public getter and private setter) from C# to VB.NET.
But after conversion VB.NET is maintaining a private field.
C# code
class DemoViewModel
{
DemoViewModel (){ AddCommand = new RelayCommand(); }
public ICommand AddCommand {get;private set;}
}
VB.NET equivalent from code converter is
Class DemoViewModel
Private Sub New()
AddCommand = New RelayCommand()
End Sub
Public Property AddCommand() As ICommand
Get
Return m_AddCommand
End Get
Private Set
m_AddCommand = Value
End Set
End Property
Private m_AddCommand As ICommand
End Class
VB.NET code generates private backing field.
Is it possible to get rid of this back field in source code (like c#)? How?
Without this feature, VB.NET source will have lots of such redundancy.
Using VB.NET, if you want to specify different accessibility for the Get and Set procedure, then you cannot use an auto-implemented property and must instead use standard, or expanded, property syntax.
Read MSDN: https://learn.microsoft.com/en-us/dotnet/visual-basic/programming-guide/language-features/procedures/auto-implemented-properties
If getter and setter have same accessibility, e.g. both are Public, then you can use the auto-property syntax, e.g.:
Public Property Prop2 As String = "Empty"
In VB.NET it's
Public ReadOnly Property Value As String
Then to access the private setter, you use an underscore before your property name
Me._Value = "Fred"
since the answer(s) above hold(s), you may introduce a Public Prop to expose the Private one. This may not be a nice solution but still less code, than expanded Property syntax
Private Property internalprop as object
Public Readonly Property exposedprop as Object = internalprop
Related
This code does not give a compile error in VS 2017 (15.9.5)?
Why could that be?
Class BugInclass
Public Property myProp As String
Public Sub MyFct()
myProp = _myProp
End Sub
End Class
note that the "_myProp" is not decalred - it is just treated as if it was "myProp".
You are using an auto-property and they are just syntactic sugar. You write this code:
Public Property myProp As String
but what actually gets compiled is this:
Private _myProp As String
Public Property myProp As String
Get
Return _myProp
End Get
Set
_myProp = value
End Set
End Property
That second snippet is what we used to have to write for all properties up until a few years ago. The auto-property is far more convenient but the old, verbose code is still there behind the scenes so the implicit backing field still exists.
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 one class with a private static (shared, since I'm in VB.BET) field and its associated public static property, since it stores one variable that should be the same to all the instances of this class.
My Class looks like this:
Public MustInherit Class NitrogenController
Private _active As Boolean
Private Shared _controlInterval As TimeSpan
Private _lastControlTime As Date
Public Property Active() As Boolean
Public Shared Property ControlInterval() As System.TimeSpan
'other properies that must be persisted
Public Function Control() As Boolean
If Not Now > _lastControlTime.Add(_controlInterval) Or Not _active Then
Return False
Else
DoControl()
_lastControlTime = Now
Return True
End If
End Function
End Class
The problem arrives when trying to binary serialize these kind of objects, since this shared field is nos being properly stored and returns to its default value when deserializing.
I suppose this is the expected behaviour, so my question is... how can I make a shared field persistent? I have read some comments to similar questions that say that this is a bad design, but it really makes sense (AFAIK) in my case, since this variable should be the same to all the object, but can be changed by the user and therefore should be stored.
Can you suggest another way of doing it?
Thanks!
What you have read, in my opinion, is correct. This is, likely, a bad design. However, if you must, there are two ways to do this with the XmlSerializer. The easy way would be to simply add a public instance (non-shared) property which has a getter and setter which simply wrap the shared property, for instance:
Public MustInherit Class NitrogenController
Public Shared Property ControlInterval As TimeSpan
Public Property CurrentControlInterval() As TimeSpan
Get
Return ControlInterval
End Get
Set(value As TimeSpan)
ControlInterval = value
End Set
End Property
End Class
If you aren't satisfied with that method, the second, more involved, option would be to override the default serialization logic by implementing the ISerializable interface.
Is there a way for implementers of an interface where a ReadOnly property is defined to make it a complete Read/Write Property ?
Imagine I define an interface to provide a ReadOnly Property (i.e., just a getter for a given value) :
Interface SomeInterface
'the interface only say that implementers must provide a value for reading
ReadOnly Property PublicProperty As String
End Interface
This means implementers must commit to providing a value. But I would like a given implementer to also allow setting that value. In my head, this would mean providing the Property's setter as part of the implementation, doing something like this :
Public Property PublicProperty As String Implements SomeInterface.PublicProperty
Get
Return _myProperty
End Get
Set(ByVal value As String)
_myProperty = value
End Set
End Property
but this will not compile as, for the VB compiler, the implementer no longer implements the interface (because it is no longer ReadOnly).
Conceptually, this should work, because, in the end, it just means Implement the getter from the Interface, and add a setter method. For "normal methods", this would be no problem.
Is there some way of doing it, without resorting to "interface hiding" or "home-made" SetProperty() method, and style having the Property behave like a Read/Write property in the implementations ?
Thanks !
--UPDATE--
(I have moved this question to a separate Question)
My question is really : "why can't this be done in VB.NET", when the following is valid in C#.NET?" :
interface IPublicProperty
{
string PublicProperty { get; }
}
with implementation :
public class Implementer:IPublicProperty
{
private string _publicProperty;
public string PublicProperty
{
get
{
return _publicProperty;
}
set
{
_publicProperty = value;
}
}
}
Now supported in Visual Studio 2015.
What's New for Visual Basic
Readonly Interface Properties
You can implement readonly interface properties using a readwrite property. The interface guarantees minimum functionality, and it does not stop an implementing class from allowing the property to be set.
In the end, I ended up with a solution that matches my goal :
users that access via the Interface see at least a getter
users that access the implementation can Read and Write.
I did this "shadowing" the implemented property like this :
'users who access through interface see only the Read accessor
Public ReadOnly Property PublicProperty_SomeInterface As String Implements SomeInterface.PublicProperty
Get
Return _myProperty
End Get
End Property
'users who work with the implementation have Read/Write access
Public Property PublicProperty_SomeInterface As String
Get
Return _myProperty
End Get
Set(ByVal value As String)
_myProperty = value
End Set
End Property
Then, depending on how you use it, you can do :
Dim implementorAsInterface As SomeInterface = New InterfaceImplementor()
logger.Log(implementor.PublicProperty) 'read access is always ok
implementor.PublicProperty = "toto" 'compile error : readOnly access
Dim implementor As InterfaceImplementor = New InterfaceImplementor()
implementor.PublicProperty = "toto" 'write access
There is nothing at a CLI level which prevents this type of implementation and as you've demonstrated it's already supported by C#. The VB.Net language just doesn't support this style of implementation.
Knowing why though is a bit tough since the decision is almost 10 years removed at this point. Very likely it was just an over site at the time interface implementation was designed.
You can't do it as the interface requires that you implement a ReadOnly Property.
Properties don't allow overloading so there is no way to implement a non-ReadOnly and also a ReadOnly.
I would suggest you either implement a Custom Setter or drop the ReadOnly from the Interface.
Without details of why you want to do this it is hard to suggest the best solution
In Visual Basic, when you implement a method or property from an interface, you can change its name and its visibility. You can leverage that capability to handle the case you are asking about. Prior to Visual Studio 2015, I often did this:
Interface:
Public Interface SomeInterface
ReadOnly Property SomeProperty As String
End Interface
Implementing Class:
Public Class SomeClass
Implements SomeInterface
Public Property SomeProperty As String
Private ReadOnly Property SomeProperty_ReadOnly As String Implements SomeInterface.SomeProperty
Get
Return Me.SomeProperty
End Get
End Property
End Class
The result is that SomeProperty is read-only when accessed through SomeInterface, but read-write when accessed through SomeClass:
Dim c As New SomeClass
c.SomeProperty = "hello" 'Write via class OK
Dim s1 = c.SomeProperty 'Read via class OK
Dim i As SomeInterface = c
Dim s2 = i.SomeProperty 'Read via interface OK
i.SomeProperty = "greetings" 'Syntax Error, interface property is read-only
If I set a Friend-level scope on a setter, like this...
Public Class MyClass
Public Property IsDirty() As Boolean
Get
Return _isDirty
End Get
Friend Set(ByVal trueFalse As Boolean)
_isDirty = trueFalse
End Set
End Property
End Class
...And then call it from another project, it works correctly. I can't do something like MyClass.IsDirty = True.
Great! That's exactly what I want.
But now if I define an interface, and I will indeed have to do that:
Public Interface IMyClass
Property IsDirty() As Boolean
End Interface
I can do something like:
Dim MyInstance as IMyClass= GetSomeInstanceOfMyClass()
MyInstance.IsDirty=True
...And, bizarrely, it runs! No exceptions are thrown, and the inner variable is set to True. It ignores the Friend scope completely!
That's hideous. What am I missing??
Note: I need this because I'm designing an API, and I want the inner API to be able to set IsDirty, but end-developers shouldn't be able to get into that. Currently I am wrapping the whole class in a facade to get this functionality, but the facade should be unecessary.
Interface methods always have public accessibility. You can't fix that by explicit interface implementation, that will only hide the class method. Simply casting the object to the interface type gives unfettered access again.
EDIT: actually, the problem is easy to solve. Just declare the property ReadOnly in the interface declaration :)
For example:
Public Interface IMyClass
ReadOnly Property IsDirty() As Boolean
End Interface
Public Class Test
Implements IMyClass
Private mIsDirty As Boolean
Private ReadOnly Property IsDirtyImpl() As Boolean Implements IMyClass.IsDirty
Get
Return mIsDirty
End Get
End Property
Public Property IsDirty() As Boolean
Get
Return mIsDirty
End Get
Friend Set(ByVal value As Boolean)
mIsDirty = value
End Set
End Property
End Class
What you are missing is the concept of inplicit and explicit interface implementation. See the answer to this question for more details.
And if you think it's hideous with a Friend setter, try setting it to Private and watch it still be accessible via the interface!