How to use Concurrent Collections .NET - Am I doing it right? - asp.net

I have a list of strings,gObject.RotationItems I want to be able to rotate through those list of strings in a thread-safe way and start over when I reach the end. I have a dictionary object retain the order for each key, whether it's Rotation1 as seen below, or some other keys, as there will be different keys.
I'm using SyncLock to make sure threads to step on each other for a true rotation. But, do I really need to use SyncLock? Since I'm using a thread-safe collection? Does it need to be coded a little differently, if I remove the SyncLock? To ensure I rotate through the list of strings uniquely, over and over.
Look over my code, I'm not sure if this is the best way to go about it, or if someone can offer a suggestion or improvement.
The code is in vb.net, but a c# suggestion will work as well.
NotInheritable Class gObject
Public Shared RotationItems As New List(Of String)
Public Shared Rotation As New Concurrent.ConcurrentDictionary(Of String, Integer)
End Class
SyncLock gObject.BindObject
Dim iRotationOrder As Integer = 0
If gObject.Rotation.TryGetValue("Rotation1", iRotationOrder ) Then
If iRotationOrder >= gObject.RotationItems.Count - 1 Then
gObject.Rotation.TryUpdate("Rotation1", 0, iRotationOrder )
Else
gObject.Rotation.TryUpdate("Rotation1", iRotationOrder + 1, iRotationOrder )
End If
Else
iRotationOrder = 0
gObject.Rotation.TryAdd("Rotation1", 0)
End If
Return gObject.RotationItems(iRotationOrder)
End SyncLock

Related

Is it bad practice to provide your own setter or should I use setproperty?

Suppose if I had the following Employee struct:
mutable struct Employee
_id::Int64
_first_name::String
_last_name::String
function Employee(_id::Int64,_first_name::String,_last_name::String)
# validation left out.
new(_id,_first_name,_last_name)
end
end
If I wanted to implement my own setproperty!() I can do:
function setproperty!(value::Employee,name::Symbol,x)
if name == :_id
if !isa(x,Int64)
throw(ErrorException("ID type is invalid"))
end
setfield!(value,:_id,x)
end
if name == :_first_name
if is_white_space(x)
throw(ErrorException("First Name cannot be blank!"))
end
setfield!(value,:_first_name,x)
end
if name == :_last_name
if is_white_space(x)
throw(ErrorException("Last Name cannot be blank!"))
end
setfield!(value,:_last_name,x)
end
end
Have I implemented setproperty!() correctly?
The reason why I use setfield!() for _first_name and _last_name, is because if I do:
if name == :_first_name
setproperty!(value,:_first_name,x) # or value._first_name = x
end
it causes a StackOverflowError because it's recursively using setproperty!().
I don't really like the use of setproperty!(), because as the number of parameters grows, so would setproperty!().
It also brings to mind using Enum and if statements (only we've switched Enum with Symbol).
One workaround I like, is to document that the fields are meant to be private and use the provided setter to set the field:
function set_first_name(obj::Employee,first_name::AbstractString)
# Validate first_name before assigning it.
obj._first_name = first_name
end
The function is smaller and has a single purpose.
Of course this doesn't prevent someone from using setproperty!(), setfield!() or value._field_name = x, but if you're going to circumvent the provided setter then you'll have the handle the consequences for doing it.
Of course this doesn't prevent someone from using setproperty!(), setfield!() or value._field_name = x, but if you're going to circumvent the provided setter then you'll have the handle the consequences for doing it.
I would recommend you to do this, defining getter,setter functions, instead of overloading getproperty/setproperty!. on the wild, the main use i saw on overloading getproperty/setproperty! is when fields can be calculated from the data. for a getter/setter pattern, i recommend you to use the ! convention:
getter:
function first_name(value::Employee)
return value._first_name
end
setter:
function first_name!(value::Employee,text::String)
#validate here
value._first_name = text
return value._first_name
end
if your struct is mutable, it could be that some fields are uninitialized. you could add a getter with default, by adding a method:
function first_name(value::Employee,default::String)
value_stored = value._first_name
if is_initialized(value_stored) #define is_initialized function
return value_stored
else
return default
end
end
with a setter/getter with default, the only difference between first_name(val,text) and first_name!(val,text) would be the mutability of val, but the result is the same. useful if you are doing mutable vs immutable functions. as you said it, the getproperty/setproperty! is cumbersome in comparison. If you want to disallow accessing the fields, you could do:
Base.getproperty(val::Employee,key::Symbol) = throw(error("use the getter functions instead!")
Base.setproperty!(val::Employee,key::Symbol,x) = throw(error("use the setter functions instead!")
Disallowing the syntax sugar of val.key and val.key = x. (if someone really want raw access, there is still getfield/setfield!, but they were warned.)
Finally, i found this recomendation in the julia docs, that recommends getter/setter methods over direct field access
https://docs.julialang.org/en/v1/manual/style-guide/#Prefer-exported-methods-over-direct-field-access

How to implement a Binary Search Tree in Julia?

I am trying to implement BST in Julia, but I encountered problem when I call insert function. When I try to create new node, the structure stays unchanged.
My code:
type Node
key::Int64
left
right
end
function insert(key::Int64, node)
if node == 0
node = Node(key, 0, 0)
elseif key < node.key
insert(key, node.left)
elseif key > node.key
insert(key, node.right)
end
end
root = Node(0,0,0)
insert(1,root)
insert(2,root)
I also tried to change zero to nothing. Next version which I tried is with defined datatypes in Node, but when I try to call insert with nothing value(similar to C Null) it gave me error.
Thank for answer.
The code has a number of issues.
One is that it is not type stable, left and right could contain anything.
The other is that setting the local variable node inside the insert function will not affect change anything.
A stylistic issue, functions that modify their arguments generally have a ! as the last character in the name, such as insert!, push! setindex!.
I think the following should work:
type BST
key::Int
left::Nullable{BST}
right::Nullable{BST}
end
BST(key::Int) = BST(key, Nullable{BST}(), Nullable{BST}())
BST() = BST(0)
function Base.push!(node::BST, key)
if key < node.key
if node.left.isnull
node.left = BST(key)
else
push!(node.left.value, key)
end
elseif key > node.key
if node.right.isnull
node.right = BST(key)
else
push!(node.right.value, key)
end
end
end
root = BST()
push!(root, 1)
push!(root, 2)
This version overloads the Julia push! function, and uses the Nullable type so that it can distinguish between a leaf node and where it needs to continue searching to find where to insert the key. This is a recursive definition, and is not optimized, it would be much faster to do it with loops instead of recursive.

Logic issue between two classes

I'm coding a classic Sokoban game. I've got a class named "Warehouse" which represents a warehouse and a class named "WarehouseItem" which is a base class for items that belong to the warehouse.
I would like the following operations to be possible:
Dim wh as Warehouse
Dim whItem as WarehouseItem
wh.Add(whItem)
wh.Remove(whItem)
whItem.Warehouse = wh
whItem.Warehouse = Nothing
The problem is that I end up with the functions above trying to call each other recursively and I don't know how to obey it (and where I am making the mistake). Here's how it looks like:
Class Warehouse
...
Items as List(Of WarehouseItem)
Sub Add(item as WarehouseItem)
Items.Add(item)
wh.Warehouse = wh // Recursive call
End Sub
...
End Class
Class WarehouseItem
...
Private mWarehouse as Warehouse
Property Warehouse As Warehouse
...
Set(wh As Warehouse)
mWarehouse = wh
mWarehouse.Add(me) // Recursive call
End Set
End Property
...
End Class
I would appreciate any advices on how can I change the code so the above operations are possible to execute.
You have an endless recursion. A calls B, and B calls A, which calls B again ... You need to break this up somehow. Generally, what you do is make WarehouseItem.Warehouse private (or at least read-only), so people always have to go through Warehouse.Add to add a WarehouseItem. That means that you don't have to override Set for WarehouseItem.Warehouse anymore, so it won't call Warehouse.Add anymore.
The problem is that each function will always call the other one. You should be checking to see if the WarehouseItem has already been added to the Items of the Warehouse, and only add it if it's not:
Class Warehouse
...
Items as List(Of WarehouseItem)
Sub Add(item as WarehouseItem)
If Not Items.Contains(item) Then
Items.Add(item)
wh.Warehouse = wh
End If
End Sub
...
End Class
You'll need to make sure that a WarehouseItem overloads the operator for Equals, otherwise Contains won't give you what you want:
Class WarehouseItem
...
Public Overloads Function Equals(other As WarehouseItem) As Boolean _
Implements IEquatable(Of WarehouseItem).Equals
If other Is Nothing Then
Return False
End If
Return (Me.Id.Equals(other.Id)) //or whatever makes warehouseparts equal
End Function
Now if you call Warehouse.Add(WarehouseItem) the first time, it will add it, and call WarehouseItem.Set(Warehouse). Warehouse.Add is then called again, but will not do anything since the item has already been added.

Simple broken For Each Loop in VB6

I am writing a Contains method for vb6 collections that hold strings.
However I cannot get the syntax right on my foreach.
What should I change?
Public Function Contains(col as Collection, key as Variant) as Boolean
Dim thing as Object '// this is the key
For Each thing in col
If CStr(key) = CStr(thing) then
Contains = True
Exit Function
End If
Next
Contains = False
End Function

.Except<T> is throwing an Exception

I have the following code:
Public Shared Function GetAvailableManufacturers() As List(Of Manufacturer)
'first get all the live orders and extract their mfrs'
Dim sos As List(Of OrderForm) = GetFormsByStatus(StockStatus.Building)
Dim unavailableMfrs As New List(Of Manufacturer)
For Each so As StockingOrder In sos
unavailableMfrs.Add(so.Source)
Next
'then remove all mfrs with an open SO from a list of all mfrs'
Dim allMfrs As List(Of Manufacturer) = Manufacturer.GetManufacturers
Return allMfrs.Except(unavailableMfrs) <----- error here
End Function
Explanation of what the above does:
GetFormsByStatus() self-explanatory
GetManufacturers() returns a list of all manufacturers in the database
My idea to get available manufacturers was to get a list of all the manufacturers in my open forms, then get a list of all manufacturers and exclude all the manufacturers in the first list, illustrated like so (pseudo):
List A: {1,2,3,4,5,6,7,8,9,10}
List B: {5,7,10}
Result: {1,2,3,4,6,8,9}
I have set up my Manufacturer class according to this article so that it can be compared, but I'm still getting this error:
Unable to cast object of type '<ExceptIterator>d__92'1[csCore.Manufacturer]' to type 'System.Collections.Generic.List'1[csCore.Manufacturer]'.
I thought at first that because during testing GetFormsByStatus() returns 0 results maybe that was causing problems, but it doesn't make sense that Except() wouldn't work if the provided list had 0 items. Can anyone spot what I'm doing wrong?
Thanks so much!
The function expects a List(Of Manufacturer) return type, not an IEnumerable(Of Manufacturer), so adding a .ToList() to the return value should fix it:
Return allMfrs.Except(unavailableMfrs).ToList()
Your function is declared as returning List(Of Manufacturer), but your Return statement is returning only an IEnumerable(Of Manufacturer). Change the return statement to:
Return allMfrs.Except(unavailableMfrs).ToList()
If you turn Option Strict On, I believe VB will catch this kind of error at compile time, instead of blowing up at runtime.
The problem is that Enumerable.Except returns IEnumerable<T>, but your return type is List(Of T).
Change your last line to:
Return allMfrs.Except(unavailableMfrs).ToList()

Resources