[RESOLVED] Exposing an instance property as shared
Suppose I have a class of objects called Porky with a property called IsHuge:
Code:
Public Class Porky
Public Property IsHuge As Boolean
End Class
Now I want to make a special kind of Porky -- let's call it UberPorky -- for which I want to change ALL instances to either IsHuge or not IsHuge. What I'd like to do is this:
Code:
Public Class UberPorky
Inherits Porky
Public Overrides Shared Property IsHuge As Boolean
Get
Return MyBase.IsHuge
End Get
Set(value As Boolean)
MyBase.IsHuge = Value
End Set
End Property
End Class
The trouble is, I can't do that. I'm not allowed to reference MyBase or Me in a Shared property. So can anyone advise me on the right way to do it?
BB
Re: Exposing an instance property as shared
the base property IsHuge is not declared as shared, if you want to that property to effect all instances declare it as shared
Re: Exposing an instance property as shared
Dont make it Shared then - if you want a property to always return one specific value then just make it always return that value:
vb Code:
Public Class UberPorky : Inherits Porky
Public Overloads ReadOnly Property IsHuge As Boolean
Get
Return True
End Get
End Property
End Class
Re: Exposing an instance property as shared
Quote:
Originally Posted by
motil
the base property IsHuge is not declared as shared, if you want to that property to effect all instances declare it as shared
Thanks Motil. I don't want all Porkys to be the same, only all UberPorkys. So I can't make the base class IsHuge property Shared.
Quote:
Originally Posted by chris128
Dont make it Shared then - if you want a property to always return one specific value then just make it always return that value:
Code:
Public Class UberPorky : Inherits Porky
Public Overloads ReadOnly Property IsHuge As Boolean
Get
Return True
End Get
End Property
End Class
Hmm. Looks like the opposite of Motil. But main thing I want is to be able to Set IsHuge to True or False for all UberPorkys, leaving ordinary Porkys unchanged. The Get isn't so important.
Any further ideas?
tia, BB
Re: Exposing an instance property as shared
I think you're going to need to explain yourself a little better, because this isn't making much sense.
Making your property Shared does not mean that it will take on the same value for every instance of UberPorky. Infact, the property isn't even accessible via any instance of UberPorky, precisely because it is Shared. You can only use it as
Code:
UberPorky.IsHuge = True
and not
Code:
Dim u As New UberPorky()
u.IsHuge = True ' doesnt work!
After reading your first post, my thought was simply to use a (Shared!) private backing field for the propery:
vb.net Code:
Public Class UberPorky
Inherits Porky
Private Shared _IsHuge As Boolean
Public Shared Shadows Property IsHuge As Boolean
Get
Return _IsHuge
End Get
Set(ByVal value As Boolean)
_IsHuge = value
End Set
End Property
End Class
But judging from your last post, that is not what you want either. You are talking about 'all UberPorkys', which I interpret as 'all instances of UberPorky'. But you cannot get/set this property for an instance of UberPorky, because it is shared.
If you do want to set the property for all instances of UberPorky, you'd need to keep a list of them and loop through it, setting them all.
Re: Exposing an instance property as shared
Quote:
Originally Posted by
NickThissen
Making your property Shared does not mean that it will take on the same value for every instance of UberPorky
as far as i know making a property / field as shared will cause all instances of the object to share the same value, I'm still learning this subject so please fix me if i'm wrong.
Re: Exposing an instance property as shared
That makes no sense because a shared property does not exist for instances of your class. There is only one value.
Suppose 'IsHuge' is a shared property, then according to you, this code:
Code:
Dim a As New UberPorky()
Dim b As New UberPorky()
a.IsHuge = True
b.IsHuge = False
would result in a.IsHuge being False, because the value is shared between instances?
Well no, because that code doesn't even work. You can't access "IsHuge" on an instance of UberPorky, because it's shared. What you can do is this
Code:
Dim a As New UberPorky()
Dim b As New UberPorky()
UberPorky.IsHuge = True
UberPorky.IsHuge = False
And now (note I'm not even using instances a and b) I hope everyone can agree that UberPorky.IsHuge will be False. There is only one value, you are not changing a value for every instance.
Re: Exposing an instance property as shared
i know that you can not call static member / method from an object instance you can call it only from a class level and that's exactly what i'm saying, memory for static member allocated only once (well you can reset it every time a new instance is created with static / shared constructor)
EDIT: you can reset its value if you won't put it inside a static constructor, otherwise it's data will be reset each time you'll create new instance.
Re: Exposing an instance property as shared
Ok, it turns out I wasn't completely right, because you can access the shared properties on an instance (though you will get a warning). But my point remains the same: you aren't accessing any property of the instance, you are using the class (shared) property, and there's only one of them.
Boops boops: is my last suggestion in post 5 what you are looking for?
Re: Exposing an instance property as shared
@Nick. I suspect keeping a List of the instances is the only way. I'll move to a real example, although I think it's been useful to start with an abstraction.
I've created a class which inherits TabPage called DBTabPage.
Code:
Public Class DBTabPage
Inherits TabPage
Public Sub New
Me.DoubleBuffered = True
End Sub
End Class
I would like to be able to switch double buffering on or off for all the DBTabPages by clicking a button. The button sub should ideally do this:
Code:
DBTabPage.DoubleBuffered = Not DBTabPage.DoubleBuffered
But I can't find a way to expose a Shared version of DBTabPage's inherited DoubleBuffered property. Have I missed something obvious? Or would it be a transgression of some OOP principle?
BB
Re: Exposing an instance property as shared
Whether it's possible or not using your current idea, I don't really know. It is a very strange way to accomplish something very simple... I'm assuming these DBTabPages are shown in a TabControl? Why not inherit the TabControl too, and add a DoubleBuffered property to that:
Code:
Private _DoubleBuffered As Boolean
Public Property DoubleBuffered() As Boolean
Get
Return _DoubleBuffered
End Get
Set(ByVal value As Boolean)
For Each tab In Me.TabPages.Cast(Of DBTabPage) 'LINQ.. use normal loop if you cant use LINQ
tab.DoubleBuffered = value
Next
_DoubleBuffered = value
End Set
End Property
Re: Exposing an instance property as shared
The list method is certainly possible. I prefer to give the class itself a Shared list of instances. This helps because I am moving everything to a UserControl instead of a tab page. But this is how it looked:
Code:
Public Class DBTabPage
Inherits TabPage
Public Shared Pages As New List(Of DBTabPage)
Public Overrides Property DoubleBuffered As Boolean
Get
Return MyBase.DoubleBuffered
End Get
Set (value As Boolean)
MyBase.DoubleBuffered = value
End Set
End Property
Public Sub New
Pages.Add(Me)
Me.DoubleBuffered = True
End Sub
'and Pages.Remove(Me) in Dispose.
End Class
The DoubleBuffered property has to be overriden to change it from Protected to Public, but it works: you can loop through DBTabPage.Pages to set all instances of DBTabPage to DoubleBuffered=False/True. It's not drastically complicated, but to make the property Shared would have been a nice simplification. I wonder why it's apparently prohibited?
BB
Re: Exposing an instance property as shared
Quote:
Originally Posted by
boops boops
I'll move to a real example, although I think it's been useful to start with an abstraction.
awww you mean Porky and UberPorky were not real examples? :(
Re: Exposing an instance property as shared
I, too, am disappointed that Porky and UberPorky are contrived examples. I was going to ask for an explanation for the project, cause it sounded like a hoot.
How about putting a shared member on the derived class, which is exposed via a property. Then, overload the base class property, and in the get or set, set the instance property to the value of the shared property. As long as the only access to the overloaded instance is via the property (as it should be), then any attempt to read or write to the property will cause it to take on the shared value. Unfortunately, for the specific property that you are talking about, this may not be adequate.
Re: Exposing an instance property as shared
My apologies, Chris and Shaggy. The legal department warned me about letting any more slip until they sorted out the licensing. But we just succeeded in taking over our Columbian competitor ¿Porqué?. Redmond has a patent pending on the upside-down question mark, so I still have to be a bit cautious, but a pre-concept relaunch is in order.
Shaggy, was this the kind of thing you had in mind?
Code:
Public Class Porky
Protected Property IsHuge() As Boolean
Get
End Get
Set(ByVal value As Boolean)
End Set
End Property
End Class
Public Class UberPorky
Inherits Porky
Private Shared _IsHuge As Boolean
Public Overloads Shared Property IsHuge() As Boolean
Get
Return _IsHuge
End Get
Set(ByVal value As Boolean)
_IsHuge = value
MyBase.IsHuge = value
End Set
End Property
End Class
Public Class ConsumerClass
Public Sub PokeFat()
UberPorky.IsHuge = True
End Sub
End Class
I regret that I always get one or the other error. If UberPorky.IsHuge is Shared as above, I am not allowed to address MyBase. If I omit Shared, the ConsumerClass complains that I can only address IsHuge through an instance. Can we get any further from here?
BB
Re: Exposing an instance property as shared
I still can't understand why you want to do it like this... If you want to set the Text property of all Buttons in a list, you loop through the list and set them individually. If you want to set the Width property of all TextBoxes in a list, you loop through the list and set them individually. If you want to set the DoubleBuffered property of all DBTabPages in a list, you loop through the list and set them individually...! Why not? Why does it have to be different in this case?
The DoubleBuffered property is an instance member, there's no getting around that. So, you cannot set it using a shared member, unless that shared member has access to a list of all instances and can loop through the list, setting each property individually (where did I hear that before? ;)).
Re: Exposing an instance property as shared
That wasn't quite where I was going. I was suggesting that the overload of IsHuge be left unshared in a fashion something like this:
Code:
Private Shared _AlternateHuge As Boolean
Public Overloads Property IsHuge() As Boolean
Get
MyBase.IsHuge = _AlternateHuge
Return _AlternateHuge
End Get
Set(ByVal value As Boolean)
_AlternateHuge = value
MyBase.IsHuge = value
End Set
End Property
By doing this (doing it correctly, anyways, as I left off the class name when accessing _AlternateHuge, for no good reason, and this foolish explanation took longer than just fixing it), anybody accessing any instance of the derived class property will see the value of the shared member, while the instance member will be set to the value of the shared member when the property is accessed for either reading or writing. As long as the value is of little significance, this would work seamlessly as far as outside observers are concerned.
Unfortunately, as I noted earlier, the actual property you are dealing with is not some insignificant state variable for the class. The drawback of the design is that any instance that accesses the member directly before the property has been accessed, will not see the shared value. For a class that was entirely built by you, that could be managed for by either always going through the property, or by setting the property to the shared value in any method that accessed the member. A hokey solution, to be sure, but consistent with the intent of the class that the external observer would see it acting as expected, regardless of the grime beneath the hood.
Since the property you are dealing with is not just an insignificant state variable, the delay between setting the shared member and accessing the property for any instance (at which time the instance property would be set from the shared member), is probably unacceptable.
Thus I agree with Nick. Just do it in a loop.
Re: Exposing an instance property as shared
I want to be able to order my UberPorkies to Jump or not, or be _IsHuge or not, without having to go through a list and address them one by one. For example, I want to be able to command:
Code:
UberPorky.AllAreHuge = Not UberPorky.AllAreHuge
Besides, I don't want to expose the list; there are spies everywhere. No matter, I can make the list Private and let them sort it out for themselves:
vb.net Code:
Private Shared _UberPorkies As New List(Of UberPorky)
Public Shared Property AreAllHuge() As Boolean
Get
For Each u As UberPorky In _UberPorkies
If u.IsHuge = False Then Return False
Next
Return True
End Get
Set(ByVal value As Boolean)
For Each u As UberPorky In _UberPorkies
u.IsHuge = value
Next
End Set
End Property
In this example Get returns False if only one UberPorky is deviant, but it could obviously be modified to return True for at least one UberPorky.IsHuge, >50% etc. Since IsHuge is Protected in the base class, I still need to Shadow it:
vb.net Code:
Public Shadows Property IsHuge() As Boolean
Get
Return MyBase.IsHuge
End Get
Set(ByVal value As Boolean)
MyBase.IsHuge = value
End Set
End Property
The list is updated in Constructors/Destructors. I have checked whether this works for my "real" protected property, Control.DoubleBuffered, and it does. So barring further comments I reckon this is thread is resolved. Thanks Nick and Shaggy (and others) for helping me think this through. Plaudits where possible. BB