Do local variables in shared method work like static variable in C? - vb.net

Will the list in this shared method keep its state throughout the life of the method? Or will a new list be created every time this method is called?
Protected Shared Function newResxNodes(ByVal newName As String, ByVal newValue As String, Optional ByVal newComment As String = "") As List(Of ResXDataNode)
Dim newResxNodesList As List(Of ResXDataNode) = New List(Of ResXDataNode)
Dim newResxNode As ResXDataNode = New ResXDataNode(newName, newValue)
If newComment <> String.Empty Then
newResxNode.Comment = newComment
End If
newResxNodesList.Add(newResxNode)
Return newResxNodesList
End Function

No, It does not work like static variables in C. It will be a new list for every call. If you want to retain the list and list items, create a shared class field.

I've done a test and it returns 3 lines.
Module Module1
Class b
Public Sub New()
Console.WriteLine("New")
End Sub
End Class
Class a
Public Shared Sub Test()
Dim c As b = New b
End Sub
End Class
Sub Main()
a.Test()
a.Test()
a.Test()
Console.ReadLine()
End Sub
End Module

Related

Setting shared values in a for/next loop

I have a shared array that needs a calculation for each index. Right now, the array is initialized in New() and executes each time an object is created, which is redundant. How can I set it up so that the array is only initialized once, when it is created? Something like a static block in Java?
I didn't initially include the code because I thought this was just a simple question. The constructor is called 64 times (working with values of bits) and he relevant code is :
' Decimal value of each bit
Public Shared bitValue(63) As Long
Public Sub New()
' Other non-relevant code here.
For index = 0 To 63
bitValue(index) = 1L << index
Next
End Sub
Just in case you are wondering what the heck I'm doing, I'm rewriting a Java program that I did that works with casting and bitwise operators. As part of learning VB, I'm working on a translation. You can get an idea of where it is headed by going to http://sourceforge.net/projects/javabitwise/.
You can initialize it right away
Class Test1
Private Shared _list As New List(Of String) From {"1", "2"}
End Class
Or do it in a shared constructor
Class Test2
Private Shared _list As List(Of String)
Shared Sub New()
_list = New List(Of String)
_list.Add("1")
_list.Add("2")
End Sub
End Class
Or check if the value is initialized or not in the new
Class Test3
Private Shared _list As List(Of String)
Public Sub New()
' Use synclock
If _list Is Nothing Then
_list = New List(Of String)
_list.Add("1")
_list.Add("2")
End If
End Sub
End Class
Or put your list in a singleton
Here's a quick example of the Singleton approach. We access the class via its Instance() function:
Public Class Form1
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Debug.Print(KibblesAndBits.Instance.bitValue(10))
End Sub
End Class
Public Class KibblesAndBits
Private Shared _Kibbles As KibblesAndBits = Nothing
Public Shared Function Instance() As KibblesAndBits
If IsNothing(_Kibbles) Then
_Kibbles = New KibblesAndBits ' the private constructor will now fire and initialize
End If
Return _Kibbles
End Function
Public bitValue(63) As Long
Private Sub New() ' Private Constructor means you can't instantiate it directly
For index = 0 To bitValue.Length - 1
bitValue(index) = index
Next
End Sub
' ... other standard Class code ...
End Class

Sharing a List of(String) between Private Sub

In my code I basically read a textbox and put each line into a list (Of String) Dim "testblock" in code below
From there I create another list (of string) and split each line whenever a space is found. Dim "block" in code below
Now I want to be able to access that list from anywhere in the project.
How do I go about sharing a List of(String) between Private Sub such as form buttons?
Private Sub PhaseCodeBTN_Click(sender As Object, e As EventArgs) Handles PhaseCodeBTN.Click
Dim testblock As New List(Of String)
Dim lines As String() = TextBox1.Text.Split(New String() {Environment.NewLine}, StringSplitOptions.RemoveEmptyEntries)
Dim block As New List(Of String)
For Each l As String In lines
testblock.Add(l)
Dim words As String() = BlockCodeBox.Text.Split(" ")
For Each splitword As String In words
block.Add(splitword)
Next
Next
BlockCodeBox.Text = testblock(BlockNumBox.Text)
WordCmdBox.Text = block(WordNumBox.Text)
End Sub
Private Sub PhaseBlackBTN_Click(sender As Object, e As EventArgs) Handles PhaseBlackBTN.Click
WordCmdBox.Text = block(WordNumBox.Text)
End Sub
Create a Public Shared Class with your List(Of String) there to use it anywhere in the project:
Public Shared Class DataHolder
Private _block As New List(Of String)
Public Property Block As List(Of String)
Get
Return _block
End Get
Set
_block = value
End Set
End Property
End Class
Example:
Either simply use DataHolder.Block.Add(splitword) OR following steps:
Declare a class variable block to use it in entire class:
Private block As List(Of String)
Initialize it in some suitable function / event-handler like Form_Load:
block = DataHolder.Block
Do the operation:
block.Add(splitword)

Duplicate Settings In Reference DLL

I have a DLL with several properties and a function that generates runs a SSRS report in the background and saves it to a PDF file.
I have a DataTable with all the reports that need to be generated and where they need to be saved.
I want to make each instance of the DLL run in a separate thread. I took a stab at it found the 2nd row in the DataTable overrode the first row.
Here is the Class/DLL Code
Public Class SSRSFunctions
Private Shared _Formated_Parameters As String
Private Shared _Report_Parameters As Dictionary(Of String, String)
Public Property FORMATED_PARAMETERS() As String
Get
Return _Formated_Parameters
End Get
Set(ByVal value As String)
_Formated_Parameters = value
End Set
End Property
Public Sub New()
_Report_Parameters = New Dictionary(Of String, String)
End Sub
Public Function RenderReportToFile() As String
'RenderReportHere
End Function
Public Sub AddParameter(ByVal Name As String, ByVal Value As String)
If _Report_Parameters.ContainsKey(Name) Then
_Report_Parameters.Remove(Name)
_Report_Parameters.Add(Name, Value)
Else
_Report_Parameters.Add(Name, Value)
End If
End Sub
End Class
Here is the calling Code
Private Sub CheckForNewRequests()
'Filter DataTable for Reports to Run
For Each dr As DataRow in DateTable.Rows
Dim rpt As New SSRSFunctions
Dim t1 As New Threading.Thread(AddressOf StartNewThread)
rpt.FORMATED_PARAMETERS = (dr("REPORT_PARAMS"))
t1.Start(rpt)
Next
End Sub
Private Function StartNewThread(ByVal report As SSRSFunctions) As String
Return report.RenderReportToFile()
End Function
I am trying to figure out why the "Dim rpt As New SSRSFunctions" is not creating a new instance of the DLL and so the second row of the dataTable has a new instance to store it's parameters.
The second row is overriding the first.
Help?
Thanks
jlimited
Dont make the private properties shared, remove the Shared keyword from the declarations.
change
Private Shared _Formated_Parameters As String
Private Shared _Report_Parameters As Dictionary(Of String, String)
to
Private _Formated_Parameters As String
Private _Report_Parameters As Dictionary(Of String, String)
By sharing them you are saying that no matter how many instances of the class is created always use (share) the same instance of the shared internal variable.

A class can only be a template for a single object not a template for a collection

I have a simple class List.vb which is the following:
Public Class List
Public fList As List(Of Integer)
Public Sub New()
fList = New List(Of Integer)
fList.Add(1)
fList.Add(2)
fList.Add(3)
fList.Add(4)
fList.Add(5)
End Sub
End Class
The Console application is using this class like the following:
Module Module1
Sub Main()
Dim fObject As List = New List
Dim cnt As Integer = 0
For Each x As Integer In fObject.fList
Console.WriteLine("hello; {0}", fObject.fList.Item(cnt).ToString())
cnt = cnt + 1
Next
Console.WriteLine("press [enter] to exit")
Console.Read()
End Sub
End Module
Can I change the class code so that List.vb is a list(of integer) type?
This would mean that in the Console code I could replace In fObject.fList with just In fObject?
Or am I barking up the wrong tree - should classes be single objects and lists should be collections of classes ?
Yes, you can do that. In order for an object to be compatible with For Each, it must have a GetEnumerator function:
Public Function GetEnumerator() As IEnumerator _
Implements IEnumerable.GetEnumerator
Return New IntListEnum(fList)
End Function
The IntListEnum class must, in turn, implement IEnumerator, like this:
Public Class IntListEnum Implements IEnumerator
Private listInt As List(Of Integer)
Dim position As Integer = -1
Public Sub New(ByVal fList As List(Of Integer))
listInt = fList
End Sub
Public Function MoveNext() As Boolean Implements IEnumerator.MoveNext
position = position + 1
Return (position < listInt.Count)
End Function
Public Sub Reset() Implements IEnumerator.Reset
position = -1
End Sub
Public ReadOnly Property Current() As Object Implements IEnumerator.Current
Get
Try
Return listInt(position)
Catch ex As IndexOutOfRangeException
Throw New InvalidOperationException()
End Try
End Get
End Property
End Class
Now you can make fList private, and iterate your List as follows:
For Each x As Integer In fObject
You can see a complete example here.
The answer that dasblinkenlight has provided is excellent, but if all you need is a list that of integers that is pre-populated, you can just inherit from List(Of Integer) and then have the class populate itself in the constructor:
Public Class List
Inherits List(Of Integer)
Public Sub New()
Add(1)
Add(2)
Add(3)
Add(4)
Add(5)
End Sub
End Class
When you inherit from List(Of Integer), your class automatically gets all of the functionality implemented by that type, so your class also becomes a list class that works the same way. Then, you can just use it like this:
Dim fObject As New List()
For Each x As Integer In fObject
Console.WriteLine("hello; {0}", x)
Next

Is it possible to make a shared function generic?

I can create classes that use generics, however I was wondering if it is possible to apply this to a shared method rather than rely on the caller casting to the correct type.
This is the method:
Public Shared Function DeserializeObject(ByVal serializedXml As String, ByVal givenType As System.Type) As Object
Dim serializer As New XmlSerializer(givenType)
Return serializer.Deserialize(New IO.StringReader(serializedXml))
End Function
I'm pretty sure this can't be done, but thought I'd check (if so Extra points will be awarded if someone can technically explain why the compiler can't do this).. Alternative suggestions would also be appreciated.
Public Shared Function StronglyTypedDeserializeObject(Of T)
(ByVal serializedXml As String) As T
Dim serializer As New XmlSerializer(GetType(T))
Return DirectCast(
serializer.Deserialize(New IO.StringReader(serializedXml))
, T)
End Function
Note that invocations will have to supply the type expected:
Dim foo As MyType
= Utility.StronglyTypedDeserializeObject(Of MyType)(sourceXml)
There's no reason you couldn't create a generic version of the function. e.g.:
Public Shared Function Deserialize(Of T)(ByVal serializedXml As String) As T
Dim serializer As New XmlSerializer(GetType(T))
Return DirectCast(serializer.Deserialize(New StringReader(serializedXml)), T)
End Function
The Following Example shows how you can do this. The esstential trick is remember that can you can use the GetType function a defined Generic for example GetType(MyObject(Of T))
Public Class Form1
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Dim Test1 As New MyObject(Of String)
Dim Test2 As New MyObject(Of Integer)
Dim Data As String = ""
Test1.Data = "Hello World"
Test2.Data = 1010101
Data = Test1.SerializeObject
Test1 = MyObject(Of String).DeserializeObject(Data)
Debug.Print(Test1.Data)
Data = Test2.SerializeObject
Test2 = MyObject(Of Integer).DeserializeObject(Data)
Debug.Print(Test2.Data)
End Sub
End Class
Public Class MyObject(Of T)
Public Data As T
Public Sub New()
End Sub
Public Shared Function DeserializeObject(ByVal serializedXml As String) As MyObject(Of T)
Dim serializer As New XmlSerializer(GetType(MyObject(Of T)))
Return serializer.Deserialize(New IO.StringReader(serializedXml))
End Function
Public Function SerializeObject() As String
Dim serializer As New XmlSerializer(GetType(MyObject(Of T)))
Dim Result As New IO.StringWriter()
serializer.Serialize(Result, Me)
Return Result.ToString
End Function
End Class
If you don't like fully qualifying the type to get at the shared member then you can do something like this.
Public Class MyObjectString
Inherits MyObject(Of String)
End Class
Then you can call MyObjectString.Deserialize