When are Shared (Static) variables created and destroyed. For example have a look at the code below:
Imports System.Data.SqlClient
Public Class Form1
Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
Person.testCon = New SqlConnection
Person.Age = 30
Dim p1 As Person
End Sub
End Class
Imports System.Data.SqlClient
Public Class Person
Public Shared testCon As SQLConnection
End Class
The testCon variable is accessible from the Form_Load before the first instance of Person is created. I realise that it is probably not good practice to have a connection as a shared variable but I want to get my point across. I also want to know when variables are created and destroyed if they are primitives (like Person.Age in the example)
Shared variables live for the length of your application, according to Microsoft.
However, object type variables are only instantiated when you tell them to be.
You can verify this behavior by creating a new test class:
Public Class Class1
Sub New()
System.Diagnostics.Debug.Fail("Class Created")
End Sub
End Class
Then create a shared variable for this class as a member variable in another class:
Private Shared m_TestClass As Class1
If you don't access the shared variable, the Debug.Fail statement will not be executed. However, as soon you instantiate this class and assign it, it will be fired (just like any other object):
m_TestClass = New Class1
Shared variables live until the AppDomain they reside in is unloaded.
You could also test this by adding a Finalize statement to the test class with a similar Debug.Fail statement.
The lifetime is one reason that you should use SyncLock when assigning new values to object-type shared variables.
Related
I made a two static classes
NotInheritable Class gObject2
Public Shared TestSyncLock As String = "test"
End Class
NotInheritable Class gObject3
Public Shared TestSyncLock As String = "test"
End Class
Then I have two aspx
Synclock1.aspx:
Public Class SyncLock1
Inherits System.Web.UI.Page
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
SyncLock gObject2.TestSyncLock
Thread.Sleep(10000)
End SyncLock
End Sub
End Class
Synclock2.aspx
Public Class SyncLock2
Inherits System.Web.UI.Page
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
SyncLock gObject3.TestSyncLock
SomeDiv.InnerHtml = "It works"
End SyncLock
End Sub
End Class
When I go to synclock1.aspx it spins for 10 seconds and shows a blank page as expected.
When I go to synclock2.aspx it spits out it works
Everything is good so far.
Now when I go to synclock1.apx and then in another browser got to synclock2.aspx, synclock2.aspx doesn't finish loading until synclock1.aspx finishes.
These are 2 different objects I'm locking with synclock, but it treats them the same. Why is this?
The SyncLockstatement takes an object reference as its argument. As the String type is a reference type, your code is satisfying that constraint. However, due to String Interning in .Net, the literal value equality of the two separate String references is also causing referential equality between gObject2.TestSyncLock and gObject3.TestSyncLock.
From: String.IsInterned Method - Remarks (emphasis added)
The common language runtime automatically maintains a table, called
the intern pool, which contains a single instance of each unique
literal string constant declared in a program, as well as any unique
instance of String you add programmatically by calling the Intern
method.
The intern pool conserves string storage. If you assign a literal
string constant to several variables, each variable is set to
reference the same constant in the intern pool instead of referencing
several different instances of String that have identical values.
Since both gObject2.TestSyncLock and gObject3.TestSyncLock are pointing to the same String reference, SyncLock gObject2.TestSyncLock will block SyncLock gObject3.TestSyncLock.
The subject code is a good example of how string interning can cause unexpected behavior. The article Interning Strings and immutability provides additional details on the mechanics of interning and also provides another example where interning can cause unexpected results.
So the moral of this story is to avoid using strings as the argument for SyncLock. It is safer to use something like the following:
NotInheritable Class gObject2
Public Shared TestSyncLock As New Object
End Class
NotInheritable Class gObject3
Public Shared TestSyncLock As New Object
End Class
As I'm self taught my VB coding is not bad but my use of OOP is poor. I'm sure this can be done but I have not found out how yet.
I am building a webforms app which needs to grab data about a user from AD. I have a Person Class which I can use as follows
Public Class _Default
Inherits System.Web.UI.Page
Dim LoggedOnPerson As Person 'Added here so available throughout class
Private strLoggedOnUser As String
Private strADDomain As String
Private strADUserID As String
Public Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
strLoggedOnUser = Request.ServerVariables("LOGON_USER").ToUpper
strADDomain = strLoggedOnUser.Split("\")(0)
strADUserID = strLoggedOnUser.Split("\")(1)
If Not IsPostBack Then
'Dim LoggedOnPerson As Person *** changed to
LoggedOnPerson = New Person
'Get details from AD for logged on user
LoggedOnPerson.GetDetails(strADDomain, strADUserID)
'Store in Session
Session("LoggedOnUser") = LoggedOnUser
'This will now give me access to details such as
'LoggedOnPerson.EmailAddress
'LoggedOnPerson.GivenName
'LoggedOnPerson.TelephoneNo etc.
Else
'Postback so pull in details from Session
LoggedOnUser = Session("LoggedOnUser")
End If
End Sub
End Class
My problem is that I cannot access LoggedOnPerson in other events. e.g.
Public Sub SaveDetails()
Dim email As String = LoggedOnPerson.Email
'This now produces correct result. No error that LoggedOnPerson is not declared
End Sub
I of course get LoggedOnPerson is not declared error. How can I get around this.
You have created the object of "Person" inside Page_Load event. Take it outside and declare at the class level. Also add that object to view state/session state on Page_Load event and typecast it to "Person" class inside other events.
I am having a really tough time with structuring a Class that is used throughout the application.
The problem is the exact same issue as described here:
Sitecore switches user session with another user
A session variable is being shared by any secondary user that logs in AFTER the first user.
My Class basically assigns a permission level to the session object, so that each page and or control can read it without doing a trip to the DB.
The Class Structure is as follows:
Public NotInheritable Class cPermissions
Public Shared Sub AssignPermissionToSession(ByVal UserID As Integer)
Private Shared Sub SetInSession(key As String, value As Dictionary(Of String, String))
Public Shared Function HasPerm(ByVal ControlName As String) as Boolean
End Class
So to explain the process: User Logs in. The login code calls cPermissions.AssignPermissionToSession(UserID). That Sub calls SetInSession which assigns the permission dictionary to a session object.
As a sidenote, I would prefer a NotInheritable class in this instance as it allows me to shorthand through the code, using the Shared Function HasPerm without instantiating the class. HasPerm reads the session object and returns true or false if the control has permission or not.
So back to the original problem, according to the previous link mentioned at the start, because the Sub is shared, I am experiencing session Hijacking.
But if I don't share the SetInSession sub, the shared sub AssignPermissionsToSession (which login needs to see) cant access it.
So basically I would really appreciate if someone could instruct me how to structure this class correctly without experiencing Accidental Session Hijacking.
Thanks in Advance!
The Code as requested is as follows (shrunk for brevity):
Public NotInheritable Class cPermissions
'local dictionary that gets created, and then assigned to session
Private Shared dPermissions As New Dictionary(Of String, String)
Public Shared Sub AssignPermissionToSession(ByVal UserID As Integer)
dPermissions.Clear()
'Here I open DB and get a list of Roles that each member may have
While ....
BuildPermissionArray()
End While
'Now dPermission should be created assign to session
SetInSession("Permissions", dPermissions)
End Sub
Private Shared Sub BuildPermissionArray()
'Here we create the local Dictionary ready for the session
'So for each role we get each permission for each control ie:
dPermissions.add(control,perm)
End Sub
Private Shared Sub SetInSession(ByVal key As String, value As Dictionary(Of String, String))
If value Is Nothing Then
HttpContext.Current.Session(key) = New Dictionary(Of String, Integer)
Else
HttpContext.Current.Session(key) = value
End If
End Sub
Public Shared Function HasPermission(ByVal PermissionType As Permission, ByVal ControlName As String) As Boolean
Dim obj As Object = HttpContext.Current.Session("Permissions")
Dim d As Dictionary(Of String, String) = DirectCast(obj, Dictionary(Of String, String))
'Here I search the dictionary and check relevant permission for the control name
Return result
End Function
End Class
Now the Login code calls:
cPermissions.AssignPermissionToSession(UserID)
And each page load reads the controls on the current page and calls:
cPermissions.HasPermission(View,"PageOrControlName")
Why is overloading called compile time polymophism and overriding called runtime polymorphism? For example, have a look at the code below:
Public Class Animal
Public Overridable Overloads Sub Eat()
MsgBox("Animal Eat no arguement")
End Sub
Public Overridable Sub Drink()
MsgBox("Animal drink arguement")
End Sub
End Class
Public Class Horse
Inherits Animal
Public Overloads Overrides Sub Eat()
MsgBox("Horse Eat no arguement")
End Sub
Public Overloads Sub Eat(ByVal food As String)
MsgBox("Horse Eat food arguement")
End Sub
Public Overloads Overrides Sub Drink()
MsgBox("Animal drink arguement")
End Sub
End Class
Public Class Form1
Private Sub Form2_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
Dim a1 As New Animal
Dim a2 As Animal
a2 = New Horse
a1.Eat()
a2.Eat("Fruit") 'line 6
End Sub
End Class
Line 6 will cause a compile time error as the program stands. However, if I add an Eat(String) to the animal class then it will compile. What is the reasoning behind this?
Also the answer in the following post says: "The Overloads keyword is optional, but if you use it for one method, you must use it for all overloads of that method: "http://stackoverflow.com/questions/1173257/overloads-keyword-in-vb-net. I am not always finding this to be the case, if the function in question also Overrides. Is this the case?
I am looking through a large program that uses polymophism with interfaces. I have supplied the class above as an example for illustration purposes.
Line 6 will cause a compile time error as the program stands. However,
if I add an Eat(String) to the animal class then it will compile. What
is the reasoning behind this?
This is because the signature exposed by the type Animal does not have an Eat version with a string, until you modified the base class (Animal) signature. Polymorphism allows you to refer to a Horse as an Animal type, but only through the Animal's signature (unless you cast it to a horse type). So if you had another type Cat, which inherited from Animal, but didn't have eat(""), that would cause a compiler error if VB were to allow what you mentioned.
Also the answer in the following post says: "The Overloads keyword is
optional, but if you use it for one method, you must use it for all
overloads of that method
I think override provides that workaround you found, but not 100% sure about it. I personally don't use Overload at all to save on typing, and since C# doesn't use it.
I don't know why they would call it compile time or runtime polymorphism, but I'll try to explain how it works:
Overriding a class member replaces the implementation of that member in the base class. This implies that you cannot override a member in its own class.
This doesn't compile:
Public Class Animal
Public Overridable Sub Eat()
' eat whatever
End Sub
Public Overrides Sub Eat()
' eat whatever
End Sub
End Class
This does compile:
Public Class Animal
Public Overridable Sub Eat()
' eat whatever
End Sub
End Class
Public Class Horse : Inherits Animal
Public Overrides Sub Eat()
' eat whatever, except meat
End Sub
End Class
In this example, I have replaced the original implementation with an implementation that does not allow the horse to eat meat. This disables any instance of Horse from eating meat products, even though the Animal type did not specify this limitation. However, to specify your own food type, you must add an overload that takes a string parameter.
Overloading a member allows you to choose either the original or the overload implementation. You can overload a member in the same class, or in a subclass that inherits from this base class. Or even in both classes.
This works:
Public Class Animal
Public Overloads Sub Eat()
' eat whatever
End Sub
Public Overloads Sub Eat(food as String)
' eat food
End Sub
End Class
This also works:
Public Class Animal
Public Overloads Sub Eat()
' eat whatever
End Sub
End Class
Public Class Horse : Inherits Animal
Public Overloads Sub Eat(food as String)
' eat food
End Sub
End Class
Conclusion
By overriding a member, you effectively disable the implementation of the base type. By overloading a member, you add an additional implementation, so either implementation can be used. You can override a member only once, but you can overload it as many times as needed.
Gotcha
If you create an instance of type Horse, but assign it to a variable of type Animal, only the members on the base class are visible, but they still use the implementation on the Horse type. To get around this, cast the instance of type Animal to the Horse type.
I have a database "Pubs" with a table "authors". I have made a dbml file from the database by dragging over "authors".
Here is the "Default.aspx.vb"
Public Class _Default
Inherits System.Web.UI.Page
Dim author As Object
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
Dim db As New PubsContext
Dim authors = From p In dbo.authors _
Select p
GridView1.DataSource = author
GridView1.DataBind()
End Sub
End Class
Here is the class for it: "Class1.vb"
Partial Public Class PubsContext
Dim authors As Object
Public Function GetProductsByCategory(ByVal id1 As Integer) As IEnumerable(Of authors)
Return From p In Me.authors _
Where p.au_id = id1 _
Select p
End Function
End Class
Error code:
"Expression of type 'Object' is not queryable. Make sure you are not missing an assembly reference and/or namespace import for the LINQ".
In references there is already a "System.Data.Linq". What should I do?
Well this is the problem:
Dim authors As Object
That's just an object. What does it mean to call Select, Where etc on that? Where are you even giving it a value? Work out what the type should really be, make sure you give it an appropriate value to start with, and you should be fine.
It's not clear why you're introducing your own authors field at all, to be honest - I'd expect the generated context to have an Authors property of type Table<Author> or something similar.
(I note that you're also trying to set GridView1.DataSource to author rather than authors, by the way... Why are you doing that? What value are you expecting the author field in _Default to have?)