Understanding Shared member in vb.net in the context explained below - vb.net

I'm using a wrapper class for accessing sql server data in vb.net from this link
ADO.NET Data Access Component for SQL Server in C# and VB.NET
Now in this link if we see the vb.net class two class level variable(SqlComm & SqlDA ) are declared as
Public Class VBDataAccess(Of TConnection As IConnection)
Shared SqlComm As SqlCommand = Nothing
Shared SqlDA As SqlDataAdapter = Nothing
and these are used in shared method of the class as follows
Public Shared Function NonQuery(ByVal CommandText As String, _
ByVal ParameterValues As List(Of SqlParameter), _
ByVal CommandType As CommandType) As Integer
Dim res As Integer = 0
Dim SqlConn As SqlConnection = Connection
SqlConn.Open()
Try
SqlComm = New SqlCommand(CommandText, SqlConn)
SqlComm.CommandTimeout = 600
SqlComm.CommandType = CommandType
If (ParameterValues IsNot Nothing) Then
For Each Parameter In ParameterValues
SqlComm.Parameters.Add(Parameter)
Next
End If
res = SqlComm.ExecuteNonQuery()
Catch ex As Exception
Throw ex
End Try
Return res
End Function
How this SqlComm will behave in case of multiple users accessing the function at same time. Is it going to create any problem ?

Related

List is empty outside of function even after adding the list outside

I am using Visual Studio, web forms, and vb.net. Why is my list count 0 outside of PopulateNames()?
I have a list at the top of my vb.net code:
Private defaultNames As List(Of ListItem) = New List(Of ListItem)()
I can add items to my list here:
'Populate cbNames with all names
Private Sub PopulateNames()
Using sqlConn As New SqlConnection(ConfigurationManager.ConnectionStrings("databasehere").ConnectionString)
sqlConn.Open()
Using sqlCmd As New SqlCommand()
sqlCmd.CommandText = "select [ID], [FirstName] from vwNames"
sqlCmd.Connection = sqlConn
Using sdr As SqlDataReader = sqlCmd.ExecuteReader()
While sdr.Read()
Dim item As New ListItem()
item.Text = sdr("FirstName").ToString()
item.Value = sdr("ID").ToString()
'Add name from database into checkboxlist
cbNames.Items.Add(item)
'Add item from checkboxlist cbNames into list defaultNames
defaultNames.Add(item)
End While
End Using
End Using
End Sub
defaultNames is count of 6 in PopulateNames() but count of 0 anywhere else. Why won't my list items save into my defaultNames list?
You need to read up on scope.
Private defaultNames As List(Of ListItem) = New List(Of ListItem)()
Is scoped to an instance of a class, and is initialized with a new list whenever the containing class is instantiated. For a form, that will most likely be whenever it is shown.
Even if you do want that private member and don’t want to expose it elsewhere, populating it the way you do is simply bad.
It should either be a parameter that gets filled, or it should be the result of a function, or the data reader should be returned and used to populate the list, or there should be a function passed in as a parameter that does something with it.
Also, although it entails more work, you probably shouldn’t be using a list item (a GUI class) whether this is a web form or winform applications. Which is why I prefer the last 2 option’s and think the last is generally best if you are going to do something with it yourself as opposed to passing it off to something else:
Private sub init()
PopulateNames(Sub(dr as IDataReader)
Dim item As New ListItem()
item.Text = dr("FirstName").ToString()
item.Value = dr("ID").ToString()
'Add name from database into checkboxlist
cbNames.Items.Add(item)
'Add item from checkboxlist cbNames into list defaultNames
defaultNames.Add(item)
End sub
End Sub
Private Sub PopulateNames(loader as Action(Of IDataReader))
Using sqlConn As New SqlConnection(ConfigurationManager.ConnectionStrings("databasehere").ConnectionString)
sqlConn.Open()
Using sqlCmd As New SqlCommand()
sqlCmd.CommandText = "select [ID], [FirstName] from vwNames"
sqlCmd.Connection = sqlConn
Using sdr As SqlDataReader = sqlCmd.ExecuteReader()
While sdr.Read()
loader(sdr)
End While
End Using
End Using
End Sub
Given this structure, if you make the PopulateNames method public, it can be used in multiple different ways. You are no longer limited to creating a list of ListItems, as all of the actual work is done in the lambda (or if you prefer in a separate function).
Assumption: This is a Winforms application.
Don't open the connection until directly before the .Execut.... To save a few indents, you can combine the connection Using and the command Using with a comma at the end of the connection Using. You can pass the CommandText and the Connection directly to the constructor of the Command.
You don't want to fill lists and, definitely, you don't want to update the user interface (comparatively, a very slow process) while the connection is open. Readers require an open connection. Just fill a DataTable and shut down the database objects.
To fill the CheckedListBox just set the DisplayMember, ValueMember and DataSource.
Private Sub PopulateNames()
Dim dt As New DataTable
Using sqlConn As New SqlConnection(ConfigurationManager.ConnectionStrings("databasehere").ConnectionString),
sqlCmd As New SqlCommand("select [ID], [FirstName] from vwNames", sqlConn)
sqlConn.Open()
Using sdr As SqlDataReader = sqlCmd.ExecuteReader()
dt.Load(sdr)
End Using
End Using
cbNames.DisplayMember = "FirstName"
cbNames.ValueMember = "ID"
cbNames.DataSource = dt
End Sub
ListItem is not a type available without a reference and Imports to a special library.
For a web application
Private Sub PopulateNames()
Dim dt As New DataTable
Using sqlConn As New SqlConnection(ConfigurationManager.ConnectionStrings("databasehere").ConnectionString),
sqlCmd As New SqlCommand("select [ID], [FirstName] from vwNames", sqlConn)
sqlConn.Open()
Using sdr As SqlDataReader = sqlCmd.ExecuteReader()
dt.Load(sdr)
End Using
End Using
cbNames.DataSource = dt
cbNames.DataTextField = "FirstName"
cbNames.DataValueField = "ID"
cbNames.DataBind()
End Sub
To access the DataTable you can either make a class level variable or create a Function and return the DataTable
Private Function GetNameData() As DataTable
Dim dt As New DataTable
Using sqlConn As New SqlConnection(ConfigurationManager.ConnectionStrings("databasehere").ConnectionString),
sqlCmd As New SqlCommand("select [ID], [FirstName] from vwNames", sqlConn)
sqlConn.Open()
Using sdr As SqlDataReader = sqlCmd.ExecuteReader()
dt.Load(sdr)
End Using
End Using
Return dt
End Function
Protected Sub Button1_Click(ByVal sender As Object, e As System.EventArgs) Handles Button1.Click
Dim dt = GetNameData()
cbNames.DataSource = dt
cbNames.DataTextField = "FirstName"
cbNames.DataValueField = "ID"
cbNames.DataBind()
End Sub

Having issues when 2 users are working with the same program

Public Class DataAccess
Dim dataAcc As New DataAccess
Public Shared dtx As New DataTable
Private Shared ConStr As String = "Server = 10.18.206.30;database=PeajeFacturacion;User ID=FacturacionUsr;Password = ukShLq?U6&hNxDxN+67!XaYq"
Public Shared Function AddOneRecord(PK As String) As DataTable
Using cn As New SqlConnection(ConStr),
cmd As New SqlCommand("Select c.idCruce, c.FechaCruce, c.HoraCruce, c.claseVehiculo, c.Importe,
c.codigoCobro, n.nomCaseta
from dbo.Cruce AS c
JOIN dbo.nombre_caseta AS n
ON n.numCaseta=c.ClavePlaza
where c.CodigoCobro = #PK;", cn)
cmd.Parameters.Add("#PK", SqlDbType.VarChar).Value = PK
cn.Open()
dtx.Load(cmd.ExecuteReader)
End Using
Return dtx
End Function
End Class
I use that part to create the connection just like the example #Mary posted. Then:
Protected Sub btnAgregar_Click(sender As Object, e As EventArgs) Handles btnAgregar.ServerClick
Dim numTicket As String = txtNoTicket.Text
Dim dtx As New DataTable
Dim pk As String
pk = txtNoTicket.Text
Dim con2 As New SqlConnection
Dim cmd2 As New SqlCommand
Dim dr As SqlDataReader
Dim dtx2 As DataTable
Dim status As Boolean = False
'If Not Integer.TryParse(ticket.Text, pk) Then
If String.IsNullOrEmpty(pk) Then
'ScriptManager.RegisterStartupScript(Me, Page.GetType, "Script", "showDisplay();", True)
cFunciones.mostrarDivAlertaAA("Type a number", "dangerNormal", Me.Page, "")
Else
dtx = DataAccess.AddOneRecord(pk)
So when adding tickets the issue is the ticket 1 user adds, gets added to the other user even though they use different sessions and different computers. The program is in test fase right now.
You can get rid of Shared in the DatAccess class. Then each instance of the class will have its own data. Now you must declare an instance of the class and call the method on that instance.
Public Class DataAccess
Dim dataAcc As New DataAccess
Public dtx As New DataTable
Private ConStr As String = "Server = 10.18.206.30;database=PeajeFacturacion;User ID=FacturacionUsr;Password = ukShLq?U6&hNxDxN+67!XaYq"
Public Function AddOneRecord(PK As String) As DataTable
Using cn As New SqlConnection(ConStr),
cmd As New SqlCommand("Select c.idCruce, c.FechaCruce, c.HoraCruce, c.claseVehiculo, c.Importe,
c.codigoCobro, n.nomCaseta
from dbo.Cruce AS c
JOIN dbo.nombre_caseta AS n
ON n.numCaseta=c.ClavePlaza
where c.CodigoCobro = #PK;", cn)
cmd.Parameters.Add("#PK", SqlDbType.VarChar).Value = PK
cn.Open()
dtx.Load(cmd.ExecuteReader)
End Using
Return dtx
End Function
End Class
Protected Sub btnAgregar_Click(sender As Object, e As EventArgs) Handles btnAgregar.ServerClick
Dim dtx As New DataTable
Dim pk = txtNoTicket.Text
If String.IsNullOrEmpty(pk) Then
cFunciones.mostrarDivAlertaAA("Type a number", "dangerNormal", Me.Page, "")
Else
Dim datAcc As New DataAccess
dtx = datAcc.AddOneRecord(pk)
End If
End Sub

Multithreading Safe Calls not populating comboboxes vb.net

just curious on what im doing wrong here, the principle should work. Can anyone give me a hand?
The Code runs fine, but seems to not add them into my comboboxes
normal thread start like so
t1 = New Thread(New ThreadStart(AddressOf GetNewClientData))
t1.Start()
data is not empty or null... :)
Function GetNewClientData()
Try
Dim con As New SqlConnection
Dim myConString As String = My.Settings.ConString
Dim objcommand As SqlCommand = New SqlCommand
With objcommand
.Connection = con
Dim cmdText As String = "SELECT distinct Applicant,Client,Market,Project from AAClient order by Client"
.CommandText = cmdText
End With
con.ConnectionString = myConString
con.Open()
Using readerObj As SqlClient.SqlDataReader = objcommand.ExecuteReader
'This will loop through all returned records
While readerObj.Read
addClientInvoke(readerObj("Client").ToString)
addApplicantInvoke(readerObj("Client").ToString)
addMarketInvoke(readerObj("Client").ToString)
addProjectInvoke(readerObj("Client").ToString)
End While
End Using
con.Close()
Catch ex As Exception
End Try
Return Nothing
End Function
Delegate Sub addApplicant(s As String)
Sub addApplicantInvoke(ByVal s As String)
If CreateNewSite.cbApplicant.InvokeRequired Then
Dim d As New addApplicant(AddressOf addApplicantInvoke)
CreateNewSite.cbApplicant.Invoke(d, New Object() {s})
Else
CreateNewSite.cbApplicant.Items.Add(s)
End If
End Sub
Delegate Sub addClient(s As String)
Sub addClientInvoke(ByVal s As String)
If CreateNewSite.cbClient.InvokeRequired Then
Dim d As New addClient(AddressOf addClientInvoke)
CreateNewSite.cbClient.Invoke(d, New Object() {s})
Else
CreateNewSite.cbClient.Items.Add(s)
End If
End Sub
Delegate Sub addMarket(s As String)
Sub addMarketInvoke(ByVal s As String)
If CreateNewSite.cbMarket.InvokeRequired Then
Dim d As New addMarket(AddressOf addMarketInvoke)
CreateNewSite.cbMarket.Invoke(d, New Object() {s})
Else
CreateNewSite.cbMarket.Items.Add(s)
End If
End Sub
Delegate Sub addProject(s As String)
Sub addProjectInvoke(ByVal s As String)
If CreateNewSite.cbProject.InvokeRequired Then
Dim d As New addProject(AddressOf addProjectInvoke)
CreateNewSite.cbProject.Invoke(d, New Object() {s})
Else
CreateNewSite.cbProject.Items.Add(s)
End If
End Sub
possibly how i'm calling the delegate??
any help is appreciated
**** thanks to #jods here is the working code with one of the invoke methods****
starting thread in another modul
t1 = New Thread(New ParameterizedThreadStart(AddressOf GetNewClientData))
t1.Start(Me)
Code within the Modul
Function GetNewClientData(ByVal oldForm As CreateNewSite)
Try
Dim con As New SqlConnection
Dim myConString As String = My.Settings.ConString
Dim objcommand As SqlCommand = New SqlCommand
With objcommand
.Connection = con
Dim cmdText As String = "SELECT distinct Applicant,Client,Market,Project from AAClient order by Client"
.CommandText = cmdText
End With
con.ConnectionString = myConString
con.Open()
Using readerObj As SqlClient.SqlDataReader = objcommand.ExecuteReader
'This will loop through all returned records
While readerObj.Read
addApplicantInvoke(readerObj("Applicant").ToString, oldForm)
addClientInvoke(readerObj("Client").ToString)
addMarketInvoke(readerObj("Market").ToString)
addProjectInvoke(readerObj("Project").ToString)
End While
End Using
con.Close()
Catch ex As Exception
MsgBox(ex)
End Try
Return Nothing
End Function
Delegate Sub addApplicant(s As String, oldform As CreateNewSite)
Sub addApplicantInvoke(ByVal s As String, ByVal oldform As CreateNewSite)
If oldform.InvokeRequired Then
Dim d As New addApplicant(AddressOf addApplicantInvoke)
oldform.cbApplicant.Invoke(d, New Object() {s, oldform})
Else
oldform.cbApplicant.Items.Add(s)
End If
End Sub
The problem is CreateNewSite.cbProject. CreateNewSite is not your form instance. It's a nifty :p VB.NET feature called the default form instance:
VB has a concept of "Default Form Instances". For every Form in the application's namespace, there will be a default instance created in the My namespace under the Forms property.
You need to pass the correct form instance (i.e. 'Me' / 'this') to your background thread.

how to declare method return value in vb.net

I've made a class named Cls_ICCID where I declare the method in Update_Status which returns a byRef variable.
Cls_ICCID
Public Sub Update_Status(**ByRef massege As String**, ByVal ICCID_No As Integer, ByVal status As Integer)
Try
Dim cmd As SqlCommand
Dim sql As String
Dim myConnection As SqlConnection = New SqlConnection()
myConnection.ConnectionString = "Data Source=TEHRANI\TEHRANI;Initial Catalog=GSMProduction;Persist Security Info=True;User ID=sa;Password=1"
sql = "UPDATE Tbl_ICCID SET Status=status WHERE ICCID=ICCIDNo"
myConnection = New SqlConnection(sql)
myConnection.Open()
cmd = New SqlCommand(sql, myConnection)
cmd.ExecuteNonQuery()
cmd.Dispose()
myConnection.Close()
massege = "SeccessFully"
Catch ex As Exception
massege = "server Error"
End Try
End Sub
And then I execute that method when a textbox change event triggers:
Private Sub Txt_ICCID_TextChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Txt_ICCID.TextChanged
Dim clsICCID As Cls_ICCID
clsICCID.Update_Status(lblError.Text, Txt_ICCID.Text, 1)
End Sub
But this gives me the exception:
Arithmetic operation resulted in an overflow.
What am I doing wrong?
to be honest, as konrad said you should really work on the basics if you want to use such kind of code.
haven't tried the code out, but i think you want something like
Public Function Update_Status(iccidNo As Integer, status As Integer) As String
Const sql As String = "UPDATE Tbl_ICCID SET Status=#status WHERE ICCID=#ICCIDNo"
Const connstr As String = "Data Source=TEHRANI\TEHRANI;Initial Catalog=GSMProduction;Persist Security Info=True;User ID=sa;Password=1"
Try
Using myConnection = New SqlConnection()
myConnection.ConnectionString = connstr
Using cmd = New SqlCommand(sql, myConnection)
cmd.Parameters.AddWithValue("#status", status)
cmd.Parameters.AddWithValue("#ICCIDNo", iccidNo)
cmd.ExecuteNonQuery()
Update_Status = "Successfully"
End Using
End Using
Catch ex As SqlException
Update_Status = "server Error"
Catch ex As Exception
Update_Status = "server Error"
End Try
End Function
but personally i would handle the exceptions not that way and return a boolean.
The thing that you specifically ask is returning value in a method. Instead of Sub you must declare it like Function and then return the value with return:
Public Function Update_Status(ICCID_No As Integer, status As Integer) As String
'...
return massege
End Function
And then catch the value:
lblError.Text = clsICCID.Update_Status(Txt_ICCID.Text, 1)
I should use from Function instead of sub method. because sub method is void.
For a method to return a value you need to declare your method as a function, instead of sub.
For example:
Public Function Update_Status(ByVal ICCID_No As Integer, ByVal status As Integer) As String
Return "errorMessage"
End Function
And can then invoke it like this:
returnValue = Update_Status(Txt_ICCID.Text, 1)
see: http://msdn.microsoft.com/en-us/library/sect4ck6%28v=vs.80%29.aspx
But it also seems that your parameters might not match up: sending a String as an Integer?

Reference to a non-shared member requires an object reference

I am getting the above error now when I run one of my ASPX pages, written in VB.NET. So I tried following the solution at:
http://msdn.microsoft.com/en-us/library/zwwhc0d0(v=vs.80).aspx
The above link seemed promising, cause it seemed to describe my problem exactly. However, I got the following error from this solution:
Compiler Error Message: BC30456:
'GlobalF2' is not a member of
'GlobalFunctions' Line 88:
DSProductData =
GlobalFunctions.GlobalF2.ComplaintTrendingDrillDown3p(FirstMonthDate,
LastMonthDate, TheLevel, ProductGroup,
TheCategory, ListNumber)
And here is my modified source code causing this error, but based off of Mike Smith's solution:
Namespace GlobalFunctions
Public Class GlobalF
Public Function ComplaintTrendingDrillDown3p(ByVal FirstMonth As DateTime, ByVal LastMonth As DateTime, ByVal rowLevel As Integer, ByVal productGroup As String, ByVal category As String, ByVal ListNumber As String) As DataSet
Dim DSPageData As New System.Data.DataSet
Dim param(5) As SqlClient.SqlParameter
param(0) = New SqlParameter("#FirstMonthDate", SqlDbType.DateTime)
param(0).Value = FirstMonth
param(1) = New SqlParameter("#LastMonthDate", SqlDbType.DateTime)
param(1).Value = LastMonth
param(2) = New SqlParameter("#TheLevel", SqlDbType.Int)
param(2).Value = rowLevel
param(3) = New SqlParameter("#ProductGroup", SqlDbType.Varchar)
param(3).Value = productGroup
param(4) = New SqlParameter("#TheCategory", SqlDbType.Varchar)
param(4).Value = category
param(5) = New SqlParameter("#ListNumber", SqlDbType.Varchar)
param(5).Value = ListNumber
''# A Using block will ensure the .Dispose() method is called for these variables, even if an exception is thrown
''# This is IMPORTANT - not disposing your connections properly can result in an unrespsonsive database
Using conn As New SQLConnection(ConfigurationSettings.AppSettings("AMDMetricsDevConnectionString")), _
cmd As New SQLCommand("ComplaintTrendingDrillDown3p", conn), _
da As New SQLDataAdapter(cmd)
cmd.CommandType = CommandType.StoredProcedure
cmd.Parameters.AddRange(param)
da.Fill(DSPageData)
End Using
Return DSPageData
End Function
End Class
Public Class CallingClass
Dim GlobalF2 As New GlobalF
Public Function ComplaintTrendingDrillDown3p(ByVal FirstMonth As DateTime, ByVal LastMonth As DateTime, ByVal rowLevel As Integer, ByVal productGroup As String, ByVal category As String, ByVal ListNumber As String) As DataSet
Dim DSPageData As New System.Data.DataSet
Dim param(5) As SqlClient.SqlParameter
param(0) = New SqlParameter("#FirstMonthDate", SqlDbType.DateTime)
param(0).Value = FirstMonth
param(1) = New SqlParameter("#LastMonthDate", SqlDbType.DateTime)
param(1).Value = LastMonth
param(2) = New SqlParameter("#TheLevel", SqlDbType.Int)
param(2).Value = rowLevel
param(3) = New SqlParameter("#ProductGroup", SqlDbType.Varchar)
param(3).Value = productGroup
param(4) = New SqlParameter("#TheCategory", SqlDbType.Varchar)
param(4).Value = category
param(5) = New SqlParameter("#ListNumber", SqlDbType.Varchar)
param(5).Value = ListNumber
''# A Using block will ensure the .Dispose() method is called for these variables, even if an exception is thrown
''# This is IMPORTANT - not disposing your connections properly can result in an unrespsonsive database
Using conn As New SQLConnection(ConfigurationSettings.AppSettings("AMDMetricsDevConnectionString")), _
cmd As New SQLCommand("ComplaintTrendingDrillDown3p", conn), _
da As New SQLDataAdapter(cmd)
cmd.CommandType = CommandType.StoredProcedure
cmd.Parameters.AddRange(param)
da.Fill(DSPageData)
End Using
Return DSPageData
End Function
End Class
End Namespace
I think Mike Smith is correct about not using Shared, cause I think that caused this problem. However, I am a newbie at VB.NET and I'm not sure how else to declare an instance as an object variable and then reference this instance by variable name. Can you help?
OK, ur solution looked very good to me. I want to make sure I implemented it correctly though. Can you compare mine to urs?
Now I get the same error I had initially...Maybe it's overwriting data in the table?
Dim gf As New GlobalFunctions.CallingClass
DSProductData = gf.GlobalF2.ComplaintTrendingDrillDown3p(FirstMonthDate, LastMonthDate, TheLevel, ProductGroup, TheCategory, ListNumber)
...
Public Class CallingClass
Public GlobalF2 As New GlobalF
'Public Function CallingClass(ByVal FirstMonth As DateTime, ByVal LastMonth As DateTime, ByVal rowLevel As Integer, ByVal productGroup As String, ByVal category As String, ByVal ListNumber As String)
' Dim cc_new As New CallingClass()
'End Function
Public Function ComplaintTrendingDrillDown3p(ByVal FirstMonth As DateTime, ByVal LastMonth As DateTime, ByVal rowLevel As Integer, ByVal productGroup As String, ByVal category As String, ByVal ListNumber As String) As DataSet
Dim DSPageData As New System.Data.DataSet
Dim param(5) As SqlClient.SqlParameter
param(0) = New SqlParameter("#FirstMonthDate", SqlDbType.DateTime)
param(0).Value = FirstMonth
param(1) = New SqlParameter("#LastMonthDate", SqlDbType.DateTime)
param(1).Value = LastMonth
param(2) = New SqlParameter("#TheLevel", SqlDbType.Int)
param(2).Value = rowLevel
param(3) = New SqlParameter("#ProductGroup", SqlDbType.Varchar)
param(3).Value = productGroup
param(4) = New SqlParameter("#TheCategory", SqlDbType.Varchar)
param(4).Value = category
param(5) = New SqlParameter("#ListNumber", SqlDbType.Varchar)
param(5).Value = ListNumber
''# A Using block will ensure the .Dispose() method is called for these variables, even if an exception is thrown
''# This is IMPORTANT - not disposing your connections properly can result in an unrespsonsive database
Using conn As New SQLConnection(ConfigurationSettings.AppSettings("AMDMetricsDevConnectionString")), _
cmd As New SQLCommand("ComplaintTrendingDrillDown3p", conn), _
da As New SQLDataAdapter(cmd)
cmd.CommandType = CommandType.StoredProcedure
cmd.Parameters.AddRange(param)
da.Fill(DSPageData)
End Using
Return DSPageData
End Function
End Class
And the error:
System.ArgumentException: Column
'QXP_SHORT_DESC' does not belong to
table Table.
The offending line:
If pException("QXP_SHORT_DESC") =
TheCategory Then
You can't dim an instance of a class outside a method you can use
public GlobalF2 As New GlobalF
EDIT
I'm not sure exactly what you are attempting to do but pulling all of the extraneous code out.
Class File
Namespace GlobalFunctions
Public Class GlobalF
Public Sub DoSomthing()
Console.WriteLine("hi")
End Sub
End Class
Public Class CallingClass
Public GlobalF2 As New GlobalF
Public x As Int16 = 3
End Class
End Namespace
Main File
Imports System.IO
Module Module1
Public Sub Main()
Dim gf As New GlobalFunctions.CallingClass
gf.GlobalF2.DoSomthing()
End Sub
End Module