I know you can obtain a lock instance members like so:
SyncLock [Object]
[Object].mutate()
End SyncLock
but how do you lock static fields?
(e.g. to make [Object's Class].[static field] = [new value] thread-safe)
I can't find anything online for VB.
The field is a primitive type.
As long as the object is a reference type, you can simply lock that object:
SyncLock [Class].[Object]
' … edit object
End SyncLock
Depending on your situation this may be the correct thing to do. However, be aware that this should ideally only be done on private objects, inside the class. Otherwise you have no guarantee that every client is going to lock the object correctly.
Whether your field is a primitive type isn’t important here, except that most primitive types are value types, and you cannot lock those. So, assuming that your type is a value type, you have to resort to a separate lock object as discussed in the comments:
Private Shared ReadOnly LockObj As New Object()
But, to clarify, locking on LockObj does not magically lock the rest of the class. It just provides a protocol for locking, and as long as every thread accessing the fields respects this protocol, you’re safe. Here’s an example:
Class Foo
Private Shared ReadOnly LockObj As New Object()
Private Shared MyValue As Integer = 1
Public Shared Sub UpdateValue()
SyncLock LockObj
MyValue += 1
End SyncLock
End Sub
Public Shared Function ReadValue() As Integer
SyncLock LockObj
Return MyValue
End SyncLock
End Function
End Class
As long as every thread uses only UpdateValue and ReadValue to access MyValue, you’re safe from race conditions.
Related
I have stored objects in a listbox. I want to READ (Not write or edit) these objects from different threads. Is this threadsafe? And if not, how would I make it threadsafe?
I tried writing a threadsafe function, but this obviously does not return a value on all exits.
Private Delegate Function GetDetailsDelegate(ByVal index As Integer)
Private Function GetDetails(index As Integer) As MySQLDetails
If InvokeRequired Then
Invoke(New GetDetailsDelegate(AddressOf GetDetails), {index})
Else
Return LstMySQL.Items.Item(index)
End If
End Function
I have an interface IValidator, and I want classes that implement IValidator to have access to a shared set of properties and methods, but it seems VBA doesn't have true implementation inheritance, so instead I have a class BaseValidator with the shared resources, which is used as a delegate in the subclasses.
Interface:
'IValidator
Public Function isValid(columnName As String) As Boolean
End Function
'used for initializing delegate
Public Sub setup(fieldsDict As Dictionary)
End Sub
Base class:
'BaseValidator
Public fieldsDict As Dictionary
Public Sub setup(fieldsDict As Dictionary)
Set Me.fieldsDict = fieldsDict
End Sub
Public Function doSomethingWithFieldsDict(columnName as string) as variant
'do something
End Function
Example implementation:
'Validator_FeatureNumber
Private bv As New BaseValidator
Implements IValidator
Public Sub IValidator_setup(fieldsDict As Dictionary)
bv.setup fieldsDict
End Sub
Function IValidator_isValid(columnName As String) As Boolean
IValidator_isValid = IsNumeric(bv.doSomethingWithFieldsDict(columnName))
End Function
This works, but it means I have to duplicate the IValidator_setup() code block in every implementation, which seems like a bad idea for code maintainability. Is there any way to have a subclass inherit methods from a superclass in VBA?
The short answer is no.
Welcome to the the fun and exiting world of 1991:) VBA is a subset of VB6. Inheritance was not supported at that time, and because Microsoft based VBA on VB6 and then abandoned* it when they went to .Net, that means it likely never will be:(
*They did update it somewhat to cope w/64 bit API calls, but that was pretty much it.
Is there a way to declare a property of type dictionary of string, string in VB.Net.
I am using this on a usercontrol to add properties via the designer.
I tried the following:
Private v As Dictionary(Of String, String)
Public Property VList As Dictionary(Of String, String)
Get
Return v
End Get
Set(ByVal value As Dictionary(Of String, String))
v = value
End Set
End Property
But when I try this the string collection editor window opens up but the add & remove buttons are disabled. What is the correct way to declare this property?
I want to add the key & value via the designer.
The Dictionary does not have a built in UITypeEditor. There are many reasons why there isn't: there are 2 Types which are generic, it also doesnt have an Item accessor, there is no simple Add method, the key must be unique and there is no built in way to serialize a Dictionary "item".
The right way is to use a Collection class inheriting from Collection<T> so you can control access to the contents (note: this is from System.Collections.ObjectModel not the horrible VB Collection!). The fast way to setup a working interface is to use a List(Of myTypeClass), but this is dangerous in production code because it allows all sorts of actions on the innerlist which you likely do not want.
<Serializable><TypeConverter(GetType(FooConverter))>
Public Class FooBar
<DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)>
Public Property Name As String
<DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)>
Public Property Value As String
' simple ctor REQUIRED for the UITypeEditor
Public Sub New()
Name = ""
Value = ""
End Sub
' ctor for the TypeConverter (NOT included)
Public Sub New(n As String, v As String)
Name = n
Value = v
End Sub
Public Overrides Function ToString
Return Name
End Sub
End Class
' must be instanced
Private myFoo As New List(Of FooBar)
' list is an object so it cant be serialized, but the CONTENTS can be
<DesignerSerializationVisibility(DesignerSerializationVisibility.Content)>
Public Property FooList As List(of FooBar)
Get
If myFoo Is Nothing Then
myFoo = New List(of FooBar)
End If
Return myFoo
End Get
Set
' do nothing
End Set
End Sub
' for designer serialization
Private Function ShouldSerializeFooList As Boolean
Return myFoo.Count > 0 ' or myFoo IsNot Nothing
End Sub
public Sub ResetMyFolist
myFoo = New List(of FooBar)
End Sub
Caveats:
It is almost always better to write a class container for the Foobar items. Usually you would inherit from Collection<T>. List<T> as shown is a container and a collection, so the contents can be cleared, reset, modified etc when exposed as shown. They are fast and easy to implement though and the basic concept is the same.
If a Dictionary is really what you want, you can write your own UITypeEditor (not UIDesigner, this is not a control) but this would probably require a great deal of work on many levels. The reason there are not gobs of them flying around is that most people make do with one of the standard collections and simply enforce unique names in other ways. (Adding "Properties" to a usercontrol, suggests that really the key or name ought to be fixed and known to the app ahead of time so it knows what it is and what to do with it(?)).
Often VS can perform designer serialization on its own with simple properties like those in FooBar. However, since they are items in a collection, you will likely need to also write a TypeConverter which can return an InstanceDescriptor, to help VS instance them. But that is a different question.
I'm kind of confused using OOP, I mean, I already know (or I guess) what's a Class, and Object, a Method, a property and things like that, but I have this doubt:
Let's supppose I have a class "Laundry" this class has (just for this example) 3 properties:
laundryID
Name
Washers
Id and Name are "primitive" types or simple types (integer and string), but Washers, represent a list of object of type "Washer", that has 3 properties:
washerID
laundryID
capacity
brand
All of them (for this example) simple/primitives types (integer,string,string).
So this my dilemma, it is correct to have a constructor like this (VB .net)
public sub new(ByVal laundryID as integer)
'' Here I'll query for the data of the Laundry on DB
'' After that I will query for every washer that belongs to this laundry
'' Then I will create a washer object for every row and add it to the
'' property "Washers" of the "Laundry"
end Sub
And inside of that constructor query for all the washers that belongs to the laundry with id=laundryID parameter, and create objects of type "Washer" and add them to the list of Laundry?
I'm not sure If I explain myself, any comment I'll be really grateful, in less words, what's the correct approach (or good practices) to work with class/objects that has properties which are complex (other class/objects).
I usually work with ADO.net probably ADO/LINQ/Entity solve this thins in an transparent way, but if they do it I don't really know it.
Note: I'm familiar with VB.net, C#, PHP, so if you prefer explain/help me using examples with its syntax, it's ok.
You have many options in the OOP world, I've included two here:
Load during the Laundry constructor
Load when the Laundry.Washers are first referenced (lazy load)
The main difference here is that if you're loading 1000 Laundry objects (say to display them in a list) you won't have the 1000 individual queries firing off to load their Washers. If someone selects the Laundry and drill down, the Washers are loaded when you need the data.
Public Class Laundry
Private _laundryId As Integer
Private _name As String
Private _washers As List(Of Washer)
Public Sub New(ByVal LaundryId As Integer)
_laundryId = LaundryId
' option one - load them when the Laundry class loads
LoadWashers()
End Sub
Public ReadOnly Property Washers As List(Of Washer)
Get
If _washers Is Nothing Then
' option two - load them the first time the washers properties are referenced
LoadWashers()
End If
Return _washers
End Get
End Property
Private Sub LoadWashers()
_washers = New List(Of Washer)
' load the washers here
'...
'...
End Sub
End Class
Your constructor is fine. You are basically saying that you can only make a Laundry Class if you have an ID number, in which case you should probably throw an exception if laundryID is not a valid id number.
I usually expose something like the Washers list as an IEnumerable(Of Washer), so that the consumers of my class can't control the list themselves.
This would be a simple example:
Public Class Laundry
Private _LaundryID As Integer
Private _LaundryName As String
Private _Washers As List(Of Washers)
Public Sub New(ByVal laundryID As Integer)
_LaundryID = laundryID
_Washers = New List(Of Washers)
'// populate washers
'// throw exception if something went wrong
End Sub
'// Properties
Public ReadOnly Property Washers As IEnumerable(Of Washer)
Get
Return _Washers
End Get
End Property
End Class
How you create a new Laundry object is up to you. It could be just an empty constructor, or a Shared function that returns a new Laundry object for you with a pre-populated ID number from the database (or wherever).
I'm playing around with an idea(never played with TypeDescriptors before), and managed to get it to work nicely. But I'm concerned about some "best practice" decisions I made during my little experiment.
I use a CustomTypeDescriptor, that receives an event from its PropertyDescriptors indicating that the values are changing or being queried.
The TypeDescriptorProvider generates a completely new instance of CustomTypeDescriptor every time GetTypeDescriptor is called, it then binds the events on the CustomTypeDescriptor to the instance object.
I'm unsure whether or not generating a new CustomTypeDescriptor each time GetTypeDescriptor is called would be a good idea(even though I had to, to get this to work). I'm also unsure if there are any consequences with binding events directly from the CustomTypeDescriptor to the instance object, especially if the CustomTypeDescriptor is dynamic.
What do you guys think? Sample code of my Provider below:
Class EntityTypeDescriptionProvider
Inherits TypeDescriptionProvider
Public Sub New(ByVal parent As TypeDescriptionProvider)
MyBase.New(parent)
End Sub
Protected Sub New()
End Sub
Public Overrides Function GetTypeDescriptor(ByVal objectType As Type, ByVal instance As Object) As ICustomTypeDescriptor
Dim _CustomTypeDescriptor As EntityTypeDescriptor
'Grabbin the base descriptor.
Dim Descriptor As ICustomTypeDescriptor = MyBase.GetTypeDescriptor(objectType, Nothing)
'If for...whatever reason the instance is empty, return the default descriptor for the type.
If instance Is Nothing Then
Return Descriptor
End If
'If the instance doesnt implement the interface I use for Descriptor customization
'(which should never happen) return the default descriptor for the type.
If Not Functions.IsImplemented(instance.GetType, GetType(ICustomTypeDescriptorEntity)) Then
Return Descriptor
End If
'
'
'some lengthy "customization" based on the state of the instance.
'
'
AddHandler _CustomTypeDescriptor.GetValue, AddressOf CType(instance, ICustomTypeDescriptorEntity).GetValue
AddHandler _CustomTypeDescriptor.SetValue, AddressOf CType(instance, ICustomTypeDescriptorEntity).SetValue
Return _CustomTypeDescriptor
End Function
End Class
I've been using this for a while and it hasnt blown up at all.
Feedback still welcome, I'm answering this to lay it to rest.