Is there a way to Overload a Property in .NET - vb.net

I've done plenty of Method Overloading, but now I have an instance where I would like to Overload a Property. The IDE in Visual Studio seems to allow it, since I can actually set up the two overloads, but I get an error saying it is not valid because they only differ in type. I think I'm missing something in my syntax?
I want to be able to use two (or more) different custom classes as the Type for my property.
Public Overloads Property myFlexibleProperty() As myCustomClass1
Get
Return _myFlexibleProperty1
End Get
Set(ByVal value As myCustomClass1)
_myFlexibleProperty1 = value
End Set
End Property
Public Overloads Property myFlexibleProperty() As myCustomClass2
Get
Return _myFlexibleProperty2
End Get
Set(ByVal value As myCustomClass2)
_myFlexibleProperty2 = value
End Set
End Property
All of the help I have found so far has been concerning Overloading Methods. Despite what the IDE is letting me do, I'm beginning to think this is not possible?

To overload something--method or property--you need for it to accept a different set of parameters. Since properties in VB.NET can accept parameters, I guess you can overload them; but they have to be different.
So you could do this:
Public Overloads Readonly Property Average() As Double
Public Overloads Readonly Property Average(ByVal startIndex As Integer) As Double
But not this:
Public Overloads Readonly Property Average() As Double
Public Overloads Readonly Property Average() As Decimal

This should not be possible. You are effectively trying to make a property that could return two different types. There is no way for the system to make the determination as to what you are trying to call.
You will have to give unique property names to each.

Your signatures are the same (only the return types differ). the compiler will not know which method you're calling. That is your problem. Change the signatures.

have you tried using a class based on an interface? Then, you could have different classes based on the same common interface and the property associated to the interface type, not the specific class itself.

There is one way
Public Enum myType
inInteger = 0
inDouble = 1
inString = 2
End Enum
Public Class clsTest
Dim _Value1 As Integer
Dim _Value2 As Double
Dim _Value3 As String
Public Property MyValue(ByVal Typ As myType) As Object
Get
Select Case Typ
Case myType.inDouble
Return _Value2
Case myType.inInteger
Return _Value1
Case Else
Return _Value3
End Select
End Get
Set(ByVal value As Object)
Select Case Typ
Case myType.inDouble
_Value2 = value
Case myType.inInteger
_Value1 = value
Case Else
_Value3 = value
End Select
End Set
End Property
End Class

It is not possible to overload properties. That being said, you could accomplish what you want by creating implicit conversions or overloading the = operator.

It would be possible to have the property operate on some special class, which supports widening conversion operators to and from the real types of interest. In some circumstances this could work reasonably well and provide a useful expansion. The biggest limitations:
If the special class/struct gets converted to type Object, it won't behave like the thing to which it's supposed to be typecast.
If the special thing is a class, then every time the property is get or set will require the instantiation of a new garbage-collected object.
Still, in some circumstances this may be a useful abstraction (especially if the base type would be a struct).

Related

Initialize a value for a shared property

I want to use a counter for how many objects are created from a single class, so I thought that a Shared Property would be the way to go. But, VB doesn't like that and says, "Cannot refer to an instance member of a class from within a shared method or shared member initializer without an explicit instance of the class"
Private _Length As Integer = 0
Public Shared Property Length As Integer
Get
Return _Length
End Get
Set(value As Integer)
_Length = value
End Set
End Property
Is there a way to initialize a shared variable, in this case to zero, and have the Property still function correctly. I used the Java get/set methodology (getLength()/setLength())and that worked fine, but I'm sure that it would be frowned up by VBers.
Also, using two variables to get/set one that is actually used seems a bit redundant. I see why it is used in the VB methodology because of the recursion that happens, but it does look strange.
The backing field _Length must also be shared.
Private Shared _Length As Integer = 0
using two variables to get/set one that is actually used seems a bit
redundant.
You don't have two variables just one which is _Length, a property just manages how you can access that variable. Note that even auto implemented properties like this use a backing-field:
Public Property Length As Int32
You just don't see it since it will be generated for you.

Serializing shared field

I have one class with a private static (shared, since I'm in VB.NET) field and its associated public static property, since it stores one variable that should be the same to all the instances of this class. So far, so good.
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!
EDIT: (sorry, I was in a hurry and couldn't complete my question until now)
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
So, the problem is that I can have several nitrogen controllers, but they should all have the same _controlInterval. That's the reason why I used a shared variable for this. But it does not preserve its value after serialization/deserialization. So... any ideas about how to do this?
Thanks!

Should I create individual properties in a class or just a method to set the values?

I am learning vb.net and I am having trouble wrapping my head around the following...
I can create several properties of a custom class and get/set values or I can create a method to set them all at once. If each property is going to allow read and write should I just make a method to assign values all at once? I assume that I am missing a very important piece here. Example:
I can create 2 properties:
Public Class Employee
Public Property LastName as string
Get
Return strLastName
End get
Set(ByVal value as string)
strLastName= value
End Set
End Property
Public Property FirstName as string
Get
Return strFirstName
End get
Set(ByVal value as string)
strFirstName= value
End Set
End Property
End Class
or I can create a method:
Public Class Employee
Public Sub AddEmployee(ByVal strLastName, ByVal strFirstName)
LastName = strLastName
FirstName = strFirstName
End Sub
End Class
I apologize for such a noob question, but any insight is greatly appreciated. thank you!
If you only have a single method, you will have to use it even if you only want to change the value of a single field.
Additionally, in such a method, if you need to validate the input, you will need to write quite a lot of code for validation that is not relevant to all of the fields.
If values must be updated together, use a method to update them together and do not provide setters.
The reality of things is that how to do this depends on what you are modelling in your class. There are no hard and fast rules that say that properties are better than methods or vice versa.
There is no reason not to support both properties and a method that sets multiple properties.
Commonly, a constructor is used to create an instance of the class and to set some properties. In VB, naming a class method "New" defines it as a constructor. In your example, if you rename your AddEmployeee method to New, you will have a perfectly fine constructor. Then you program can create new instances as such:
Dim emp1 as New Employee("Burdell", "George")

Why can't define get type and set type distinctly within Properties?

Here is the problem, I wanted to define a property which accepts decimal numbers and do some process on the value and return string such as the below:
Public Property Amount() As String
Get
Return Utility.PaddingRight(Me.msAmount.ToString(), 10)
End Get
Set(ByVal vsValue As Decimal)
Me.msAmount = vsValue
End Set
End Property
But compilers warns "Set parameters must have the same type of the containing property."
It doesn't look like it should throws an error since it looks legit.
The reason that you can't is because what you put into a property should be exactly the same as what you get out of it. If the type changed then this condition would never be true. Microsoft's spec says that "Properties are like smart fields". Imagine if a field (class variable) changed between reading and writing.
Your goal is completely valid but that's not the intended use for properties. (By "intended goal" I mean Microsoft's intended goal.) Your design would also opens doors for potential problems if an invalid or null string were passed in. One of the design goals for properties is that they are light weight and shouldn't throw errors. They can but shouldn't. The recommended solution is to use the TryParse pattern for your property.
EDIT
Sorry, my brain was sidetracked, your goal is changing the getter, not the setter. The pattern that you're looking for is just a read-only property (as #msarchet pointed out) that's specific to your getter. For instance, AmountForPrint or something. You should still include a read/write for your actual value, too.
Public ReadOnly Property AmountForPrint
Get
Return Me.Amount.ToString()
End Get
End Property
Public Property Amount As Integer
Get
End Get
Set(value As Integer)
End Set
End Property
I think you need a to do this with a method not a property
Public Function Amount(ByVal value As Decimal) As String
End Function
This is just a shot in the dark . . .
Set(ByVal vsValue As String)
Me.msAmount = System.Convert.ToDecimal(vsValue)
End Set
You'd be far better off doing this as such
Public Read Only Property Amount() As String
Get
Return Utility.PaddingRight(Me.msAmount.ToString(), 10)
End Get
End Property
Public Sub SetAmount(ByVal value As Decimal)
Me.msAmount = value
End Sub

Is it correct to correct properties values on the fly?

Is it correct to correct properties values on the fly?
for example: (note the .ToLower)
Public Property X() As String
Get
Return _x.ToLower
End Get
Set(ByVal Value As String)
_x = value.ToLower
End Set
End Property
There is nothing incorrect about standardizing your properties in getter/setters. Without any context of what X represents it is hard determine if a property is the right way to access and update the value of X. Depending on the application, it might make sense to not have a public setter at all but instead have a method such as CustomerRequestedXToChange(XUpdatedValue as String)
Some improvements to your code though:
Be sure that _x is private so that no other classes can modify the value.
Only perform ToLower on the setter, not both. As long as you follow the next convention that should work fine.
All calls to _x within this class should go through X, that way the value of _x will be correct.