I am not quite clear as to why or when to use Interfaces. Can someone post a complete, simple and small example of an Interface using VB.NET in a Console Application. How is it extensible?
In short: Favor Composition over Inheritance
Interfaces are simply a common set of member definitions that you want one or more classes to support. The key is that you have to provide the functionality explicitly when you implement an interface.
You can achieve similar results using inheritance since two sub-classes can inherit fully-functional members from the base. But the downside of inheritance is that your sub-classes end up having a hard dependency on the base class.
Consider the following classes:
Public Class Car
Publc Sub OpenDoor(ByVal key As MyKey)
Console.WriteLine("Access granted to car.")
End Sub
End Class
Public Class House
Public Sub OpenDoor(ByVal key as MyKey)
Console.WriteLine("Access granted to house.")
End Sub
End Class
You could say that these two classes are somewhat related because they both have an OpenDoor() method. You might be tempted to even create a base class to extract common functionality.
Public Class OpenableProperty
Public Sub OpenDoor(ByVal key As MyKey)
Console.WriteLine("Access granted to property.")
End Sub
End Class
Public Class Car
Inherits OpenableProperty
End Class
Public Class House
Inherits OpenableProperty
End Class
You could then use this abstraction like this:
Public Class SecurityService
Public Sub InspectProperty(ByVal item As OpenableProperty)
Dim key As New MyKey()
Console.WriteLine("Inspecting property...")
item.OpenDoor(key)
End Sub
End Class
However, relating a house to a car based solely on the fact that you can access them with a key is a pretty weak abstraction. Heck, even a can of beans can be openable!
But there are other points where relation might occur as well. For example, both a car and a house might have air conditioning:
Public Class Car
Inherits OpenableProperty
Public Sub TurnOnAirConditioning()
Console.WriteLine("Cool breezes flowing in car!")
End Sub
End Class
Public Class House
Inherits OpenableProperty
Public Sub TurnOnAirConditioning()
Console.WriteLine("Cool breezes flowing in house!")
End Sub
End Class
Should TurnOnAirConditioning() be extracted to the base class too? What does it have to do with being an OpenableProperty? Could a JewelrySafe class inherit from OpenableProperty without an AC? The better answer in this situation is to extract Interfaces and use these to compose the functionality in our classes rather than inherit:
Public Interface IOpenable
Sub OpenDoor(ByVal key As MyKey)
End Interface
Public Interface ICoolable
Sub TurnOnAirConditioning()
End Interface
Public Class Car
Implements IOpenable, ICoolable
Public Sub OpenDoor(ByVal key as MyKey) Implements IOpenable.OpenDoor()
Console.WriteLine("Access granted to car.")
End Sub
Public Sub TurnOnAirConditioning() Implements ICoolable.TurnOnAirConditioning()
Console.WriteLine("Cool breezes flowing in car!")
End Sub
End Class
Public Class House
Implements IOpenable, ICoolable
Public Sub OpenDoor(ByVal key as MyKey) Implements IOpenable.OpenDoor()
Console.WriteLine("Access granted to house.")
End Sub
Public Sub TurnOnAirConditioning() Implements ICoolable.TurnOnAirConditioning()
Console.WriteLine("Cool breezes flowing in house!")
End Sub
End Class
Public Class JewelrySafe
Implements IOpenable
Public Sub OpenDoor(ByVal key as MyKey) Implements IOpenable.OpenDoor()
Console.WriteLine("Access granted to jewelry safe.")
End Sub
End Class
Then your abstractions can be consumed as such:
Public Class SecurityService
Public Sub InspectProperty(ByVal item As IOpenable)
Dim key As New MyKey()
Console.WriteLine("Inspecting property...")
item.OpenDoor(key)
End Sub
End Class
Public Class ThermostatService
Public Sub TestAirConditioning(ByVal item as ICoolable)
Console.WriteLine("Testing Air Conditioning...")
item.TurnOnAirConditioning()
End Sub
End Class
The SecurityService could then be used to inspect the Car, House, and JewelrySafe, while the ThermostatService could be used only to test the AC of the Car and House.
Sub Main()
Dim securityService As New SecurityService()
Dim thermostatService As New ThermostatService()
Dim house As New House()
Dim car As New Car()
Dim jewelrySafe As New JewelrySafe()
With securityService
.InspectProperty(house)
.InspectProperty(car)
.InspectProperty(jewelrySafe)
End With
With thermostatService
.TestAirConditioning(house)
.TestAirConditioning(car)
End With
End Sub
Which should produce the following results:
Inspecting property...
Access granted to house.
Inspecting property...
Access granted to car.
Inspecting property...
Access granted to jewelry safe.
Testing Air Conditioning...
Cool breezes flowing in house!
Testing Air Conditioning...
Cool breezes flowing in car!
Consider this simple interface:
Public Interface IWeightedValue
Public ReadOnly Property Weight As Double
Public ReadOnly Property Value As Double
End Interface
Without even writing any more code, I can start dealing with this concept in other parts of my code. For instance:
Public Function GetWeightedAverage(ByVal points As IEnumerable(Of IWeightedValue)) As Double
Dim totalWeight As Double = 0.0
Dim totalWeightedValue As Double = 0.0
For Each point As IWeightedValue in points
totalWeight += point.Weight
totalWeightedValue += (point.Weight * point.Value)
Next
Return totalWeightedValue / totalWeight
End Function
And voila -- now for any class I write, if I just make it implement IWeightedValue then I can calculate the weighted average for a collection of instances of this class.
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
I am tired of creating a System.Web.UI.LiteralControl everytime I need to add a control to my in webforms. So, I decided that it would help me if I created a custom LiteralControl that initialized with that value.
So, I created this very simple class:
Public Class ScriptLiteralControl
Inherits System.Web.UI.LiteralControl
Private _Text As String
Public Sub New()
Me.InitControl()
End Sub
Private Sub InitControl()
Me._Text = "<script type=""text/none""></script>"
End Sub
Public Overrides Property Text As String
Get
Return Me._Text
End Get
Set(value As String)
Me._Text = value
End Set
End Property
End Class
But when I do this in my webpages:
dim slc as New ScriptLiteralControl
Me.Header.Controls.Add(slc)
Absolutely nothing gets added.
According to the ASP.NET documentation I've read, all I had to do was basically override the Text property in my implementation but that doesn't seem to be working.
Can someone tell me what obscure .net rule I am not following in my implementation?
You shouldn't have to override the Text property. I think that's what's causing your problem. Try this:
Public Class ScriptLiteralControl
Inherits System.Web.UI.LiteralControl
Public Sub New()
Me.Text = "Put your script text here"
End Sub
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.
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.
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.