Override Public Readonly property - vb.net

Having a bit of a brain fart, right before bed. But i have the need to remap a ReadOnly Property from one name to a specified name i want.
I figured i could do
Public Readonly Property DocName as String
Get
Return Mybase.Name
End Get
End Property
And yes i am trying to remap the Name Property for an XMLDocument object. Just want to make sure that as long as i declare this property and then type:
Public Overrides ReadOnly Property Name As String
Get
Return SomeValue
End Get
End Property
I will be good togo? I know i will get the method has multiple definitions with identical signatures message, which brings me to my 2nd Question:
How do i prevent the Multiple Signatures error message from popping up with this type of declaration?
Unless i am missing some declaration attribute for this type of override.

You can use Shadows to accomplish this:
Public Class A
Public ReadOnly Property Name As String
Get
Return "Name"
End Get
End Property
End Class
Public Class B
Inherits A
Public ReadOnly Property DocName As String
Get
Return MyBase.Name
End Get
End Property
Public Shadows ReadOnly Property Name As String
Get
Return "SomeValue"
End Get
End Property
End Class

Related

Overload resolution works for normal method but not for constructor

My goal is to have a series of overloads, where the correct version of a method gets called depending on the type of the parameter (known only at runtime). However, I've run into an interesting problem in a case where the method I want to overload is a constructor.
Take the following inheritance structure:
Public MustInherit Class A
Public Property Common As String
End Class
Public Class X
Inherits A
Public Property Unique1 As String
Public Property Unique2 As String
End Class
Public Class Y
Inherits A
Public Property Unique3 As String
Public Property Unique4 As String
End Class
Base class A is inherited by both X and Y.
Now take this class which I'll use to show the problem:
Public Class Foo
Public Sub New(v As X)
Common = v.Common
Prop1 = v.Unique1
Prop2 = v.Unique2
Prop3 = "Some value"
Prop3 = String.Empty
End Sub
Public Sub New(v As Y)
Common = v.Common
Prop1 = "Some value"
Prop2 = String.Empty
Prop3 = v.Unique3
Prop4 = v.Unique4
End Sub
Public ReadOnly Property Common As String
Public ReadOnly Property Prop1 As String
Public ReadOnly Property Prop2 As String
Public ReadOnly Property Prop3 As String
Public ReadOnly Property Prop4 As String
Public Shared Sub Bar(v As X)
End Sub
Public Shared Sub Bar(v As Y)
End Sub
End Class
There is a normal method Bar with an overload, and also a constructor New with an overload. The first New has the same signature as the first Bar, and the second New has the same signature of the second Bar.
Finally take this test code:
Public Sub Test()
Dim Param As Object = New X
'This works fine
Foo.Bar(Param)
'This gives a compile error
Dim Thing As New Foo(Param)
End Sub
The compiler seems to have no problem with the call to Bar, but for the constructor call I get the following compile error:
Overload resolution failed because no accessible 'New' can be called without a narrowing conversion:
'Public Sub New(v As X)': Argument matching parameter 'v' narrows from 'Object' to 'X'.
'Public Sub New(v As Y)': Argument matching parameter 'v' narrows from 'Object' to 'Y'.
Why does the constructor call cause an error while the call to Bar does not.
Also, if I change the Param declaration to Dim Param As A = New X, then neither of them will compile.
I feel like I should understand this one, but for whatever reason I don't. Could someone fill me in on why this doesn't work, and maybe suggest a work-around?
While it's still unclear exactly what you are trying to achieve, an Answer is the only reasonable place to share code. Here is an attempt at solving your problem with Option Strict On, using an interface to define the properties that a class must have in order to be passed to a Foo for its construction.
Note the comments in the code which also help explain things.
This abstracts things so that Foo doesn't have to know about all the types derived from A - it only knows about the interface. In fact, it 'inverts' the relationship so that A and its derived types know what is necessary for Foo (per the interface). The rest is the implementation of X and Y, where the definitions of Props 1 through 4 now live (instead of in the various overloaded Foo constructors). This collapses the number of constructors for Foo down to just one.
The logic for translating properties of a class derived from A into Foo's properties has to live somewhere. By pushing this logic out of Foo and instead into the derived classes, you can avoid the narrowing issues that Option Strict Off defers until runtime. In addition, adding a new Z class derived from A is easy, and you don't have to modify Foo to immediately use it.
But again, as it's not perfectly clear what you intend to do with this sample code, it's hard to know if this approach 'works' for what you are thinking of, or not.
Option Strict On
Module Module1
Sub Main()
Dim Param As A = New X
Dim Thing As New Foo(Param)
Param = New Y
Thing = New Foo(Param)
'if you make a new class Z which Inherits A, it will immediately be translatable to Foo
'albeit with all String.Empty properties unless you override the properties from A
End Sub
End Module
'Defines what a Foo wants, what a Foo needs
Public Interface IPropertiesForFoo
ReadOnly Property Common As String
ReadOnly Property Prop1 As String
ReadOnly Property Prop2 As String
ReadOnly Property Prop3 As String
ReadOnly Property Prop4 As String
End Interface
Public MustInherit Class A
Implements IPropertiesForFoo
Public Property Common As String
#Region "IPropertiesForFoo implementation"
'these are Overridable, so derived classes can choose what to change and what not to
'note these are all Protected, so only derived classes know about them. Users of A may not care.
'This is just one choice;
' you could also use Throw New NotImplementedException (instead of Return String.Empty)
' and force derived classes to handle every property
Protected Overridable ReadOnly Property IPropertiesForFoo_Prop1 As String Implements IPropertiesForFoo.Prop1
Get
Return String.Empty
End Get
End Property
Protected Overridable ReadOnly Property IPropertiesForFoo_Prop2 As String Implements IPropertiesForFoo.Prop2
Get
Return String.Empty
End Get
End Property
Protected Overridable ReadOnly Property IPropertiesForFoo_Prop3 As String Implements IPropertiesForFoo.Prop3
Get
Return String.Empty
End Get
End Property
Protected Overridable ReadOnly Property IPropertiesForFoo_Prop4 As String Implements IPropertiesForFoo.Prop4
Get
Return String.Empty
End Get
End Property
'private, and doesn't need to be Overridable, as Common can map directly
Private ReadOnly Property IPropertiesForFoo_Common As String Implements IPropertiesForFoo.Common
Get
Return Common
End Get
End Property
#End Region
End Class
Public Class X
Inherits A
Public Property Unique1 As String
Public Property Unique2 As String
Protected Overrides ReadOnly Property IPropertiesForFoo_Prop1 As String
Get
Return Unique1
End Get
End Property
Protected Overrides ReadOnly Property IPropertiesForFoo_Prop2 As String
Get
Return Unique2
End Get
End Property
Protected Overrides ReadOnly Property IPropertiesForFoo_Prop3 As String
Get
Return "Some value"
End Get
End Property
'doesn't need to override Prop4; leave it as String.Empty
End Class
Public Class Y
Inherits A
Public Property Unique3 As String
Public Property Unique4 As String
Protected Overrides ReadOnly Property IPropertiesForFoo_Prop1 As String
Get
Return "Some value"
End Get
End Property
'doesn't need to override Prop2; leave it as String.Empty
Protected Overrides ReadOnly Property IPropertiesForFoo_Prop3 As String
Get
Return Unique3
End Get
End Property
Protected Overrides ReadOnly Property IPropertiesForFoo_Prop4 As String
Get
Return Unique4
End Get
End Property
End Class
Public Class Foo
Public Sub New(v As IPropertiesForFoo)
Common = v.Common
Prop1 = v.Prop1
Prop2 = v.Prop2
Prop3 = v.Prop3
Prop4 = v.Prop4
End Sub
Public ReadOnly Property Common As String
Public ReadOnly Property Prop1 As String
Public ReadOnly Property Prop2 As String
Public ReadOnly Property Prop3 As String
Public ReadOnly Property Prop4 As String
End Class
For that matter, depending on what the rest of Foo actually does, you may not even need Foo - just pass around your instances of A, since they are also IPropertiesForFoo. Then pull out their properties labeled as Prop1, Prop2, as needed. (Again, your simplified sample source doesn't hint at the larger context enough to know if this approach fits well, or not.)
I'm sure I'll get plenty of people telling me again that I shouldn't be doing things this way, but here's what I did to actually solve the problem as I needed it:
Public Class Foo
Public Sub New(v As X)
End Sub
Public Sub New(v As Y)
End Sub
Public Shared Function Create(v As X) As Foo
Return New Foo(v)
End Function
Public Shared Function Bar(v As Y) As Foo
Return New Foo(v)
End Function
End Class
Which lets me use Foo like this:
Dim Param As Object = New Y
Foo.Create(Param)
Yes, the above uses late binding and loosely-typed code. But it also keeps redundant code to a minimum, requires no lengthy interface definition or implementation, is still completely predictable, and does exactly what I want. I do consider features like this useful and valid when used in the right context.
I do still wish I could get some answer as to why the overload resolution works with a normal method but not a constructor. But for now I guess I'll just have to settle for this work-around.

Retrieve object name

I need to retrieve the name of an instanced object (not the type name...)
I have seen that the GetProperties() function gets the child properties name but i need the name of the current object
Public Class Class1
Private mValore As String
Public Property Valore As String
Get
Return mValore
End Get
Set(value As String)
mValore = value
End Set
End Property
End Class
Public Class Class2
Private mMickey As new Class1
Public Property Mickey As Class1
Get
Return mMickey
End Get
Set(value As Class1)
mMickey = value
End Set
End Property
End Class
I need to obtain inside Class1 the name of instanced object in Class2: "Mickey"
Is it possible ?
Thanks in advice for all that will answer me.
As mentioned by Hans Passant, objects don't have names.
So if you really need names, you may introduce them, as a property or field. You may employ CallerMemberNameAttribute to automatically pass the caller name to e.g. constructor.
Another thing, objects might be created outside Class2, indeed in the Mickey ... Set setter you are assigning mMickey field to an object from somewhere outside, so the object might have a different name. I would prefer to create a copy of object instead of just assignment, then we can assign any name to it and it will not collide with the previous name. An example could be:
Imports System.Runtime.CompilerServices
Public Class Class1
Private mValore As String
Public ReadOnly Name As String
Public Sub New(mValore As String, <CallerMemberName> Optional callerMemberName As String = Nothing)
Me.mValore = mValore
Me.Name = callerMemberName
End Sub
Public ReadOnly Property Valore As String
Get
Return mValore
End Get
End Property
End Class
Public Class Class2
Private mMickey As Class1
Public Property Mickey As Class1
Get
Return mMickey
End Get
Set(value As Class1)
mMickey = New Class1(mValore:=value.Valore)
End Set
End Property
End Class
If Class2 only has one property, you can just get the only property's name
Public Class Class1
Public ReadOnly Property Valore As String
Get
Return GetType(Class2).GetProperties().Single().Name
End Get
End Property
End Class
Public Class Class2
Public Property Mickey As Class1
End Class
Or if it has multiple properties, you can just get the first property's name
Public Class Class1
Public ReadOnly Property Valore As String
Get
Return GetType(Class2).GetProperties().First().Name
End Get
End Property
End Class
Public Class Class2
Public Property Mickey As Class1
Public Property Mouse As String
End Class
That returns the first property in order in which the properties are defined. So if the order is changed, it breaks.
Surely there must be more qualifying information to lead us to a solution. Can I make the assumption that you are only interested in the name of the property whose type is Class1? Then you can also filter on the property's type
Public Class Class1
Public ReadOnly Property Valore As String
Get
Return GetType(Class2).GetProperties().Where(Function(pi) pi.PropertyType Is GetType(Class1)).Single().Name
End Get
End Property
End Class
Public Class Class2
Public Property Mouse As String
Public Property Mickey As Class1
End Class
I think this is exactly what you're looking for. But if not, let me know and we can work it out.

Newsoft JSON .NET Deserializing to an Object with Private Properties in VB.net

I am currently writing an API which is taking objects from a web service handling it in VB.net using the Newsoft JSON .NET library.
I'm deserializing a JSON array called Vehicles into a list of vehicles.
Here is the important code snippets:
Public Class VehicleList
Public Vehicles() As Vehicle
End Class
Public Class Vehicle
Public Property licence_plate_number As String
End Class
Here we have a web client that grabs the json and put it into the objects.
Public Class dcVehicles
Private Property _Vehicles As VehicleList
Public ReadOnly Property Vehicle As Vehicle()
Get
Return _Vehicles.Vehicles
End Get
End Property
Public Sub Refresh()
_Vehicles = JsonConvert.DeserializeObject(Of VehicleList)(wcReply, jsSettings)
End Sub
End Class
There's slightly more to it (cut it down).
So everything is working as intended, json net is creating an array of vehicles.
I'm trying to achieve this with the properties in the vehicle class as private and read only, the applications using the api should not be able to set these.
The problem is I've tried changing the public property in the vehicle class to keep the property private and allow readonly as below:
Public Class Vehicle
Friend Property licence_plate_number As String
Public ReadOnly Property RegistrationNumber As String
Get
Return licence_plate_number
End Get
End Property
End Class
The problem I then get is that JSON.net is unable to populate the vehicles. All 3 classes are in the same namespace.
So I tried licence_plate_number with the Friend/private access level modifier but still Json net is unable to populate the object.
The only way is keeping it as Public.
Does anyone have an idea for a work-around? Or is am I missing something simple?
Thanks
If you just want to serialize a Private or Friend property with Json.NET, mark it with <JsonProperty> and mark the public readonly property you don't want to serialize with <JsonIgnore>:
Public Class Vehicle
<JsonProperty> _
Friend Property licence_plate_number As String
<JsonIgnore> _
Public ReadOnly Property RegistrationNumber As String
Get
Return licence_plate_number
End Get
End Property
End Class
Demo fiddle.
But if you really want read-only value semantics for the licence_plate_number property so that it cannot be set after construction, you can do this by replacing the default constructor with a single parameterized constructor and matching the constructor argument names to the JSON property names, like so:
Public Class Vehicle
Private Readonly licence_plate_number As String
Public Sub New(ByVal licence_plate_number as String)
Me.licence_plate_number = licence_plate_number
End Sub
<JsonProperty("licence_plate_number")> _
Public ReadOnly Property RegistrationNumber As String
Get
Return licence_plate_number
End Get
End Property
End Class
When there is a single public constructor that is parameterized, Json.NET will call it, matching the constructor arguments to the JSON properties by name using reflection and using default values for missing properties. Matching by name is case-insensitive, unless there are multiple matches that differ only in case, in which case the match becomes case sensitive.
Demo fiddle.
If your class has multiple public constructors, mark the one to use with <JsonConstructor>.

How can I control the element names of serialized subclasses?

Let's say I have the following class structure (simplified from my real-world problem):
Public Class PC_People_Container
Private _people_list As New List(Of PL_Person)
Public Sub New()
End Sub
Public Sub Add(ByVal item As PL_Person)
_people_list.Add(item)
End Sub
Public Property PeopleList As List(Of PL_Person)
Get
Return _people_list
End Get
Set(ByVal value As List(Of PL_Person))
_people_list = value
End Set
End Property
End Class
Public Class PL_Person
Private _Name As String
Public Property Name As String
Get
Return _Name
End Get
Set(ByVal value As String)
_Name = value
End Set
End Property
Private _Contacts As ContactObject
Public Property Contacts As ContactObject
Get
Return _Contacts
End Get
Set(ByVal value As ContactObject)
_Contacts = value
End Set
End Property
Public Sub New()
End Sub
End Class
Public Class ContactObject
Public Property PhoneNumber As String
Public Property EmailAddress As String
Public Sub New()
End Sub
End Class
If I were to serialize this, I'd get the default assigned node names in my XML. That means my root is named PC_People_Container and each person in the list is marked up as PL_Person. I know I can change the root node using <XmlRoot(ElementName:="PeopleContainer")>. The trouble is doing that for the subclasses. I can't use the <XmlRoot> tag on PL_Person class because there can't be two root elements, and IntelliSense throws a fit when I try to use the <XmlElement> tag on a class like I would on a property. Is it even possible to control what those subclasses are named when they're serialized as child nodes?
PL_Person and ContactObject are not subclasses as you call them, they are merely property types.
This makes your question confusing because it suggests you may have a problem with inheritance (subclasses are classes that inherit from some base class) when in fact you just want your property elements to be named differently.
You should decorate your properties (not classes) with <XmlElement> to specify custom name:
<XmlElement("Persons", GetType(PL_Person))>
Public Property PeopleList As List(Of PL_Person)
As an afterthought, I would definitely not recommend calling your classes using such an awkward convention. In .NET, you should not use any prefixes or underscores in class names. Just call it Person.

VB.Net Properties - Public Get, Private Set

I figured I would ask... but is there a way to have the Get part of a property available as public, but keep the set as private?
Otherwise I am thinking I need two properties or a property and a method, just figured this would be cleaner.
Yes, quite straight forward:
Private _name As String
Public Property Name() As String
Get
Return _name
End Get
Private Set(ByVal value As String)
_name = value
End Set
End Property
I'm not sure what the minimum required version of Visual Studio is, but in VS2015 you can use
Public ReadOnly Property Name As String
It is read-only for public access but can be privately modified using _Name
Public Property Name() As String
Get
Return _name
End Get
Private Set(ByVal value As String)
_name = value
End Set
End Property
One additional tweak worth mentioning: I'm not sure if this is a .NET 4.0 or Visual Studio 2010 feature, but if you're using both you don't need to declare the value parameter for the setter/mutator block of code:
Private _name As String
Public Property Name() As String
Get
Return _name
End Get
Private Set
_name = value
End Set
End Property
I find marking the property as readonly cleaner than the above answers. I believe vb14 is required.
Private _Name As String
Public ReadOnly Property Name() As String
Get
Return _Name
End Get
End Property
This can be condensed to
Public ReadOnly Property Name As String
https://msdn.microsoft.com/en-us/library/dd293589.aspx?f=255&MSPPError=-2147217396
If you are using VS2010 or later it is even easier than that
Public Property Name as String
You get the private properties and Get/Set completely for free!
see this blog post: Scott Gu's Blog