Cover | Table of Contents | Colophon
Hello with a single
method named Write. Save the listing to a file
named hello.vb. The rest of the
chapter will use this listing as a foundation of discussion.
Option Strict On
Imports System
Namespace Greeting
Public Class Hello
Public Sub Write(ByVal value As String)
Console.WriteLine("Hello, {0}!", value)
End Sub
End Class
End Namespace
C:\>vbc /t:library hello.vb
/t: option is short for target,
which can be one of the following values:
exe
Hello with a single
method named Write. Save the listing to a file
named hello.vb. The rest of the
chapter will use this listing as a foundation of discussion.
Option Strict On
Imports System
Namespace Greeting
Public Class Hello
Public Sub Write(ByVal value As String)
Console.WriteLine("Hello, {0}!", value)
End Sub
End Class
End Namespace
C:\>vbc /t:library hello.vb
/t: option is short for target,
which can be one of the following values:
exe
/t switch is
omitted, this is the default value.
winexe
library
Hello class from Example 2-1 is a
member of a namespace called Greeting denoted by
the Namespace block surrounding its definition.
Even if the namespace block were removed, the
Hello class would still be considered a member of
the root namespace, which is scoped to the
executable.
System and several
other namespaces. Notice the second line of code in Example 2-1:
Imports System
System namespace into the
scope of the current file, hello.vb. This is done for the benefit of the
call to Console.WriteLine, which writes a message
to the console window. Without the Imports
directive, the Console class could be referred to
only through its namespace, which means the call would look like
this:
Public Class Hello
Public Sub Write(ByVal value As String)
System.Console.WriteLine("Hello, {0}!", value)
End Sub
End Class
Console.WriteLine, things could
get ugly. As most of the .NET class library is contained within the
System namespace, importing it is usually your
best option.
Imports System
Imports Greeting
Public Class Application
Public Shared Sub Main( )
Dim hw As New Hello( )
hw.Write("World")
Console.ReadLine( )
End Sub
End Class
Greeting namespace defined in Example 2-1 was imported. Without it, every class in the
Greeting namespace would have to be referenced
directly, as in the following code:
Public Shared Sub Main( )
Dim hw As New Greeting.Hello( )
hw.Write("World")
End Sub
Public Shared Sub Main( )
Hello class (which is defined in the
component) and call its Write method.
/r
compiler option. Assuming that the DLL
lives in the same directory as the client code, this executable can
be compiled as follows:
C:\>vbc /t:exe /r:hello.dll hello-client.vb
/out
compiler option:
C:\>vbc /t:exe /r:hello.dll /out:hello.exe hello-client.vb
Hello, World!
Connection, Command, and
Recordset objects (among others) found in ADO. In
.NET, the concept of an assembly is roughly
analogous to that of a component, but you can think of it as more of
a "super component."
Sub Main entry
point or a class library in a DLL.
C:\>ildasm hello.dll
// Microsoft (R) .NET Framework IL Disassembler. Version 1.0.3705.0
// Copyright (C) Microsoft Corporation 1998-2001. All rights reserved.
.assembly extern mscorlib
{
.publickeytoken = (B7 7A 5C 56 19 34 E0 89 )
.ver 1:0:3300:0
}
.assembly extern Microsoft.VisualBasic
{
.publickeytoken = (B0 3F 5F 7F 11 D5 0A 3A )
.ver 7:0:3300:0
}
.assembly hello
{
.hash algorithm 0x00008004
.ver 0:0:0:0
}
.module hello.dll
// MVID: {8A2071A6-F906-43C1-B6DB-CA5058F54BC4}
.imagebase 0x00400000
.subsystem 0x00000002
.file alignment 512
.corflags 0x00000001
// Image base: 0x03090000
//
// ============== CLASS STRUCTURE DECLARATION ==================
//
.namespace Greeting
{
.class public auto ansi Hello
extends [mscorlib]System.Object
{
} // end of class Hello
} // end of namespace Greeting
// =============================================================
// =============== GLOBAL FIELDS AND METHODS ===================
// =============================================================
// =============== CLASS MEMBERS DECLARATION ===================
// note that class flags, 'extends' and 'implements' clauses
// are provided here for information only
.namespace Greeting
{
.class public auto ansi Hello
extends [mscorlib]System.Object
{
.method public specialname rtspecialname
instance void .ctor( ) cil managed
{
// Code size 7 (0x7)
.maxstack 8
IL_0000: ldarg.0
IL_0001: call instance void [mscorlib]System.Object::.ctor( )
IL_0006: ret
} // end of method Hello::.ctor
.method public instance void Write(string 'value') cil managed
{
// Code size 12 (0xc)
.maxstack 8
IL_0000: ldstr "Hello, {0}!"
IL_0005: ldarg.1
IL_0006: call void [mscorlib]System.Console::WriteLine(string,
object)
IL_000b: ret
} // end of method Hello::Write
} // end of class Hello
// =============================================================
} // end of namespace Greeting
//*********** DISASSEMBLY COMPLETE ***********************
// WARNING: Created Win32 resource file C:\hello.resMessageBox class in one of your applications, you
need to make sure that the System.Windows.Forms assembly is made
available to the compiler. This assembly contains the
System.Windows.Forms namespace, which in turn
contains the MessageBox class. The command-line
statement needed to compile your source code is:
vbc /t:winexe /r:System.Windows.Forms.dll mycode.vb
vbc /t:library /r:<path>\mylib.dll mycode.vb
sn -k hello.snk
System and
Microsoft.VisualBasic namespaces, respectively (a
small portion of the System namespace is also
contained in System.dll).
System namespace is the root namespace of
primary types in .NET and contains the base data types used by all
languages in the framework. When you declare a primitive data type in
VB, it is actually mapped to a type defined in this namespace. Table 2-1 provides a list of the types in
System and how they relate to Visual Basic.
|
System
|
Visual Basic
|
Description
|
Byte
|
Byte
|
8-bit unsigned integer
|
Int16
|
Short
|
16-bit signed integer
|
Int32
|
Integer
|
32-bit signed integer
|
Int64
|
Long
|
Namespace [Namespace Name]
Public Class [Class Name]
'Member variables
'Methods
'Properties
'Events
End Class
End Namespace
Hello. Shared entities are mutual across all class
instances, so you don't need an actual instance of
the class to call the method:
Console.WriteLine(World.Hello( ))
class block (with or
without an initial state).
Byte, Short,
Integer, and Long. Example 3-2 illustrates the definition of member variables
in a class.
Public Class World
'Member data represents state
Private age As Double
'Constants
Public Const AverageDensity As Single = 5515 '(kg/m3)
Public Const PolarRadius = 6356.8 'In km
Public Const SatelliteCount As Byte = 1 'The Moon
'Enums
Public Enum Continents
Africa = 1
Antarctica = 2
Asia = 3
Australia = 4
Europe = 5
NorthAmerica = 6
SouthAmerica = 7
End Enum
Public Shared Sub Hello( )
Console.WriteLine("Hello, World!")
End Sub
End Class
weight, a programmer often writes two functions.
One function is used to get the value of weight,
and another to set the value—something akin to
get_Weight and set_Weight. To
provide read-only access, the programmer would forego the
get_ method.
get_ and set_ method behind the
scenes. Essentially, a property is nothing more than language
convenience. Check it out with ILDASM.
ReadOnly, WriteOnly, or both.
Read-only properties contain a Get block that
allows retrieval of a value, but prevents it from being changed:
Public ReadOnly Property Age( ) As Double
Get
Return Me.age
End Get
End Property
Set block, which allows values to
be initialized but not retrieved:
Public WriteOnly Property Age( ) As Double
Set
'age is a Private member variable
Me.age = value
End Set
End Property
Public Property Age( ) As Double
Get
Return Me.age
End Get
Set (ByVal value As Double)
Me.age = value
End Set
End Property
Set block, you can specify the name and
type of the incoming value. If you choose not to, the compiler uses
"value" as the placeholder for the
property value.
ReadOnly keyword can also be applied to member
data. These fields can be initialized during object construction, but
not after. Usually, member data, like the private member
Function keyword and can contain
any number of parameters. They can also return a result to the caller
with the Return keyword:
Public Class SpaceTime
'In meters per second
Private Const LightSpeed As Double = 299792458
Private Function Energy(mass As Double) As Double
'Same as LightSpeed * LightSpeed * mass
Return LightSpeed *= LightSpeed * mass
End Function
'Really technical stuff goes here
End Class
Sub keyword:
Public Class SpaceTime
Public Sub FoldSpace( )
'Suprisingly simple
End Sub
End Class
Public,
Private, Protected, and
Friend.
Public
Public
classes are
visible to everyone and not restricted in any way.
Public members are visible inside and outside the
class in which they were declared.
Private
Private
classes can
only be nested within another class and are completely restricted
outside of that scope; it is not possible to declare a standalone
class with this modifier. Private classes
encapsulate functionality that is specific to the class where they
were declared.
Private member variables are accessible only
within the current class where they were declared. Even derived
classes do not have access to
Private members; they can be accessed through
properties.
Private is the most restrictive modifier.Short,
Integer, and Long
(System.Int16, System.Int32,
and System.Int64). Value types are created on the
stack, which is the area of memory that is local to a method. When
the location is destroyed, the value type is destroyed—the
garbage collector does not manage the stack.
Imports System
Public Class App
Private Class Counter
Public Sub Increment(ByVal x As Integer)
x += 1
End Sub
End Class
Public Shared Sub Main( )
Dim cc As New Counter( )
Dim x As Integer = 1
cc.Increment(x)
Console.WriteLine(x.ToString( ))
Console.WriteLine( )
Console.WriteLine("Hit ENTER to continue.")
Console.ReadLine( )
End Sub
End Class
1 because a copy of x was
passed to the Counter.Increment method. It is
useful to use the ByVal keyword explicitly instead
of relying on the default behavior:
Public Sub Increment(ByVal x As Integer)
ByVal with ByRef
causes a reference to be passed instead of a copy. A reference is
similar to a pointer. However, a reference should be thought of as an
alias of a data type, not some arbitrary location in memory.
Public Sub Increment(ByRef x As Integer)
2.System.Object. However, value types
are treated differently in terms of allocation. When a value type is
passed to a ByVal method, the actual value is
copied. Also, assigning a value type to another instance of that type
causes the value to be copied. The exception occurs when a value type
is a reference type's data member; then it is heap
allocated right along with the rest of the class.
number1 and
number2 are two distinct locations in memory that
each contain the value 5:
Dim number1 As Integer = 5 Dim number2 As Integer = number1
Dim object1 As New Object( ) Dim object2 As New Object( ) object2 = object1
object2 is now a reference to
object1. The location in memory formerly
associated with object2 is now sitting around
waiting to be garbage collected.
Point structure:
Public Structure Point
Public x As Integer
Public y As Integer
End Structure
Point is declared, it can be used just like
any other value type. There is no need to use the
New operator because the default constructor is
called automatically:
'After assignment p1 and p2 are two different points Dim p1 As Point Dim p2 As Point p1.x = 10 p1.y = 10 p2 = p1
New, which makes perfect sense
because this is what is called when you declare a new instance of an
object. The following fragment calls the default
constructor for the Hello class:
Dim hello As New Hello( ) 'Calls Hello.New( )
Public Class Hello
Public Sub New( )
Console.WriteLine("Hello, World!")
End Sub
End Class
New so it takes any number of arguments. In fact,
you can define as many different versions of New
as you want for the same object, as long as each has a different
function signature. This process is called overloading, and it looks
like this:
Public Class New
Public Sub New( )
Console.WriteLine("Hello, World!")
End Sub
Public Sub New (name As String)
Console.WriteLine("Hello, {0}", name)
End Sub
End Class
Protected methods
and a nonderived class can use the Public or
Friend (if in the same assembly) methods.
Public Class Log
Public Sub Write(ByVal msg As String)
#If Debug Then
Console.WriteLine(msg)
#End If
End Sub
End Class
Log.Write were already scattered throughout your
object model. You could always rewrite Log.Write
every time you wanted to send the message to a different location,
but that's not too practical either. OOP involves
code reuse, not code rewrite. That wouldn't exactly
lead to a class that you could share with your friends and neighbors.
Log class which
method to call in order to do the logging. Then you could switch
methods at runtime—perhaps even incorporating several different
logging methods: logging to a local text file or sending debug
messages to a remote debug window.
Public interfaces should have as few
parameters as they can. Member data should always be
Private. If it is not, think long and hard about
why it isn't. Remember, changes to a class are
easier to accommodate if information is hidden.
Wash, you really might be writing a method that
should be in Car.