Once you have a type object, you can find out if it’s a class, an interface, a structure, and so on, what methods it has, and the number and types of fields it contains.. The most common
Trang 1Figure 2-2.Shared assemblies are located in the GAC.
If the Culture entry is blank for an assembly, it means that it’s culture-neutral, which iscommon for assemblies that contain only code If you develop applications that require local-ization, it’s recommended that you isolate all of your resources in a separate assembly so thatthey can be swapped out easily with a different culture without affecting your code Sharedassemblies bring us to the concept of assembly naming Assemblies can be named in twoways:
• Strongly (or fully) named: An assembly that has a four-part name consisting of the short
assembly name, a version number, a culture identifier in ISO format, and a hash token
If an assembly is named with all four parts, it’s considered to be strongly named
• Partially named: An assembly that contains only the short assembly name and a
ver-sion number
Shared assemblies must be strongly named, and only strongly named assemblies can beregistered in the GAC The strong names are required so that the consuming application canidentify the assembly and thus verify that it’s safe to use Registering an assembly in the GAC isanalogous to registering a COM server in the registry If the assembly is not strongly named, itmay only be used locally by the application To deploy a shared assembly, use the command-line utility gacutil.exe This utility is used to view, install, and uninstall assemblies in theGAC Table 2-1 describes some of the available command-line switches that you can use withgacutil.exe:
Trang 2Table 2-1.gacutil.exe Command-Line Switches
/u Remove the assembly from the GAC, if no other references to it exist
/il Use a text file containing assembly names to be installed
/ul Use a text file containing assembly names to be removed
/l Display a listing of installed assemblies
■ Note Using partially named assemblies with the /uor /ulswitches may remove multiple assemblies
Loading Assemblies
The assembly loader goes through a very detailed process, called probing, to load an assembly.
The loader attempts to locate and load an assembly based on the exact version number in the
manifest However, you can direct the loader to load a different version of an assembly by
specifying it in a config file such as the application config file, the machine config file, or a
publisher policy file (a file that directs an application to use a newer version of an assembly)
The loader looks for partially named assemblies in the same directory as the running
applica-tion or in a subdirectory If an assembly is strongly named, then the loader will first search the
GAC before probing local directories
The assembly loader follows a certain process to locate the correct assembly during ing This series of steps is quite detailed, and you can find more about how the runtime loads
prob-assemblies on Microsoft’s developer website (see Resources), but here’s the process in a
nut-shell:
1. The runtime first checks any config files for the correct version of the assembly that it’sloading
2. If the assembly has already been loaded, the runtime will use the loaded assembly
3. The loader checks the GAC, and if it finds the assembly, it loads it
4. The runtime then follows certain probing rules, first looking in the location specified
by a <codebase> element in a config file or publisher policy The loader attempts tolocate the file based on the location, the assembly name, culture information, and version
5. If the loader can’t locate the assembly after probing for it, an error is thrown
When architecting your application, keep in mind that there’s overhead when locatingand loading assemblies This is something to consider when it comes to deciding on the num-
ber of assemblies you want to create As you can see, versioning plays a key role at assembly
load time, and all assemblies are versioned Versioning is something that was built into the
Trang 3CLR loader from the beginning and removes the affliction, affectionately known as DLL Hell,
that occurs when replacing a shared DLL with a newer version breaks applications that usethe older version In the CLR, multiple versions of the same assembly can exist simultaneously
on the same machine without conflicting with each other Moreover, applications can choose
to default to using the most recent version of an assembly on the machine, or you can specifythe exact version they prefer by applying a version policy in their configuration files
Cross-Language Compatibility
Because assemblies are self-describing and contain portable IL code, they are easily sharedacross multiple languages Finally, there’s a viable solution for creating complex systems inwhich components are coded using different languages For example, in a complex systemused for engineering analysis, you may have a group of VB developers coding the system infrastructure and a group of engineers developing the mathematical components Manyengineers still program in languages such as FORTRAN, and this works because there areFORTRAN compilers available that emit IL and create managed assemblies Thus, each development group can work in a language that’s more natural to them and to their problemdomains Metadata is the key to cross-language compatibility The metadata format is com-pletely described in the CLI Ecma standards documents
Metadata: Better Than COM
It’s easy to gloss over the importance of metadata and the advantages it offers As you’ve seen,all managed modules are self-describing through the use of metadata Metadata is not a newconcept, but its implementation in NET, in concert with the CTS, is a huge improvement overCOM, solving many of its shortcomings
Language interoperability issues that existed in COM have been resolved because nowany NET language must conform to the CLI standard and support all the necessary types
In COM, a component written in one language didn’t guarantee it could by used by anotherlanguage For example, a C++ component may not have been usable by a VB program because
it could contain types unsupported by VB
Assembly metadata also alleviates inconsistencies that were experienced in COM Ifyou’ve created COM components, you may know that there were two options for metadata:Interface Description Language (IDL) and type libraries (TLBs) IDL is a platform-independ-ent description language for interfaces and components Typically, you provide your
consumer with the COM component packaged in either a DLL or an EXE along with the IDL.The consumer typically takes the IDL and passes it through an IDL compiler to produce nativecode that the consumer can then interface with
A TLB serves much the same purpose as IDL, but it’s in binary format that high-level guages such as VB typically consume Unfortunately, IDL and TLBs don’t overlap entirely, andsome things can be described in IDL but not in TLBs and vice versa All assemblies created in.NET follow the same metadata format, so you never have to worry about consumers access-ing your objects Additionally, assembly structure and manifests mean no more issues related
lan-to registry entries and versioning that were prevalent with COM applications
Metadata is an extensible format for describing the contents of assemblies If it’s notexpressive enough for your needs, you can define new, custom “attributes” that are easily
Trang 4included in the metadata for a type In the managed world, just about every entity in a
pro-gram with a type can have metadata attached to it, including classes, interfaces, methods,
parameters, return values, assemblies, and so on You define custom attributes by deriving
from the System.Attribute class Then you can easily associate an instance of your custom
attribute to just about any entity in your assembly
To top it all off, you can access metadata at run time For example, at run time, you caniterate over all the fields of an arbitrary class type without having to know its declaration
ahead of time or at compile time This power opens up the possibility of entire programs and
types being generated dynamically at run time
Reflection
With metadata, you can programmatically access and examine type definitions and the
attrib-utes attached to them Metadata can tell you if a particular object’s class supports a given
method before attempting to call it or if a given class is derived from another The process of
inspecting metadata is called reflection Classes in the System.Reflection namespace are used
to retrieve type information at run time Typically, you start with a System.Type object when
you reflect upon types in the assembly Once you have a type object, you can find out if it’s a
class, an interface, a structure, and so on, what methods it has, and the number and types of
fields it contains
Summary
In this chapter, we covered the essentials of how a VB program is compiled, packaged, and
executed We looked at how your VB code gets compiled into IL and is then compiled on the
fly by the JIT compiler One of the requirements for JIT compilation is an expressive and
extensible mechanism that the compiler can understand—thus, we have assemblies By
pack-aging IL into assemblies that are self-documenting, both the CLR and the JIT compiler have all
the information they need to manage code execution Private assemblies make it possible to
run multiple versions of code without having to worry about registry entries or overwriting
COM components Shared assemblies provide the ability to access the functionality of a single
assembly from multiple applications Now that you have an idea of how VB programs run,
we’ll jump into some VB syntax in the next chapter
Trang 6VB Syntax
This chapter is an introduction to the syntax of the Visual Basic (VB) language The topics
covered here are the glue that binds programs together We’ll take a close look at types and
variables, since the common type system (CTS) is a key component of the NET common
language runtime (CLR) By the same token, the type system is one facet of VB that is very
different in NET from previous versions We’ll also look at namespaces; this is a NET concept
you’ll put into practice as soon as you write your first program Understanding namespaces
not only helps you navigate the VB namespaces to find the classes you need, but it also helps
you to create your own namespaces in a logical manner We’ll wrap up with an overview of VB
control flow statements, which differ in syntax but are the same in concept across all
lan-guages
In this chapter, we assume you have some experience with a previous version of VB
Although it’s obvious that the VB language was designed to leverage the knowledge of VB
developers, you’ll notice that it’s quite a departure from Visual Basic 6 (VB6) If you’re coming
from a VB6 development background, some of the new language features may be new to you,
but it won’t be long before you feel right at home with VB syntax
Types and Variables
Types in VB can be either value types or reference types Value types, such as structures and
built-in types, are allocated on the stack and contain their associated data Reference types,
such as classes and arrays, are allocated on the managed heap, while a reference (pointer) to
the object is stored on the stack As we progress through this chapter, we’ll discuss types and
variables in more detail Chapters 4 and 5 will continue the discussion in greater depth
Strong Typing
VB is a strongly typed language Well, to be more precise, VB can be a strongly typed language.
Strong typing means that every variable and object instance that’s declared must be of a
well-defined type A strongly typed language provides rules for how variables of different types can
25
C H A P T E R 3
Trang 7interact with each other Strongly typed variables enable the compiler to check that the tions being performed on variables and objects are valid For example, suppose you have amethod that computes the average of two integers and returns the result The method isdeclared in VB as follows:
opera-Function ComputeAvg(ByVal Param1 As Integer, ByVal Param2 As Integer) As DoubleComputeAvg = (Param1 + Param2) / 2
End Function
This method accepts two integers and returns a double Therefore, if you attempt to callthis method and pass in two Customer objects, you’ll receive a compile-time error Now, let’swrite the method slightly differently:
Function ComputeAvg(ByVal Param1 As Object, ByVal Param2 As Object) As Object
ComputeAvg = (Convert.ToInt32(Param1) + Convert.ToInt32(Param2)) / 2End Function
The second version of ComputeAvg() is still valid, but you have forcefully stripped away thetype information You could pass in String, Boolean, or Customer objects, and you wouldn’treceive an error until run time when the function attempts to convert the parameters This isbecause every object and value in VB derives from System.Object The Object keyword in VB
is an alias for the class System.Object It’s perfectly valid to declare parameters as type Object;however, Object is not a numeric type In order to perform the calculation, you must first
“cast” the objects into integers The result is also returned as an instance of type Object If you attempt to pass two Customer objects, the compiler won’t return an error because thoseobjects both derive from System.Object, as every other class does Although this version of themethod seems more flexible, this flexibility comes at the price of type safety and performance.Needless to say, it’s always best to find bugs at compile time rather than run time If youwere to use the first version of ComputeAvg() and try to pass in anything other than integers,you wouldn’t be able to compile the application Type safety is one of the tenets of develop-ment in NET, and the language is designed to support it
The reason I say that VB can be strongly typed is that, in contrast to C#, it supports
unde-clared variables This means you can reference a variable without first declaring it with a Dim, Private, or Public declaration VB will create any undeclared variables as type Object The two settings that affect strong typing and variable declaration in VB are Option Explicitand Option Strict
Option Explicit: Option Explicit enforces the declaration of variables When OptionExplicit is set On within a file, any variable must be explicitly declared If Option Explicit
is On and you have an undeclared variable, you’ll receive a compiler error If OptionExplicit isn’t specified in the file, the compiler default is On In this snippet, you’ll receive
a compiler error on the last line, because the variable VarUndeclared is not declared where If Option Explicit was Off, both the variables VarDeclared and VarUndeclaredwould be valid When this code compiles, VB will define VarUndeclared as type Objectuntil it’s assigned, at which point it will implicitly convert it to a Double because of its dataassignment:
any-Option Explicit On
…Dim VarDeclared As Double
Trang 8VarDeclared = ComputeAvg(108, 7933)VarUndeclared = ComputeAvg(108, 7933)Option Strict: The Option Strict setting is related to any implicit data conversions that
VB performs on variables Option Strict only allows widening conversions If OptionStrict is On, VB will only allow variables to be converted from one data type to anotherdata type in which no data loss would occur If a variable is being converted and theresultant type has less precision or smaller capacity, a compiler error will be generated
Option Strict also disallows late binding If Option Strict isn’t specified, the compilerdefault is Off Using the second ComputeAvg function shown previously, you can see thatthe following code will fail at compile time because Option Strict won’t allow an implicitconversion from Object to Double If Option Strict was Off, this code would compile andrun:
Option Strict On
…Dim x As Double = 0.0
x = ComputeAvg(108, 7933)Function ComputeAvg(ByVal Param1 As Object, ByVal Param2 As Object) As ObjectComputeAvg = (Convert.ToInt32(Param1) + Convert.ToInt32(Param2)) / 2End Function
You should always keep Option Explicit and Option Strict set to On in your tions, primarily because you’ll avoid having to debug some devious errors that only appear at
applica-run time This practice ensures that your code is strongly typed and is consistent with the type
safety of other NET languages
■ Note In VB6, you may have used the Variantdata type to store and pass parameters of different data
types, because a Variantvariable can hold data of any type Also, if you used undeclared variables, VB6
would create them as Variant This data type is no longer supported in NET, and the Objecttype is used
instead
Type Categories
Every entity in a VB program is an object that lives in memory on either the stack or the
man-aged heap Where an entity is allocated depends on whether it’s a value type or a reference
type Every method is defined in a class or module declaration (which is really a class under
the hood) Even the built-in value types, such as Integer, Long, and Double, implicitly have
methods associated with them In VB, it’s perfectly valid to write a statement such as this:
Console.WriteLine(108.ToString())
Trang 9This statement returns the string value "108" A statement like this seems unfamiliar ifyou’re used to programming in VB6 However, this syntax emphasizes how everything in VB is
an object, even down to the most basic types In fact, the keywords for the built-in types in VBare actually aliases that are mapped directly into types in the System namespace You can electnot to use the built-in VB types and explicitly use the types in the System namespace, but thispractice is discouraged as a matter of style Table 3-1 lists the built-in types with their size andcorresponding types in the System namespace
Table 3-1.VB Intrinsic Types
of the CTS and is designed to foster language interoperability by defining the features that arestandard across each language This is needed because even though the CLR supports a richset of built-in types, not all languages that create managed code support all other languagetypes For example, in the past, VB didn’t support unsigned types, whereas C# did So thedesigners of the CLI defined the CLS to standardize types and facilitate interoperabilitybetween the languages
If your application will be entirely VB-based and won’t create any components consumedfrom another language, then you don’t have to worry about adhering to the strict guidelines ofthe CLS But if you work in a project that builds components using various languages or youknow there’s a chance that your components will be called from other languages in the future,then conforming to the CLS is much more of a consideration
Trang 10In the managed world of the CLR, any data type must be one of two kinds of types:
Value type: In VB, a value type can be any one of the intrinsic data types, a structure, or an
enumeration Value types live on the memory stack, which is much faster to accessbecause the type’s value is actually stored in the stack and can be popped off the stackwhen the type variable goes out of scope A value type variable resides on the managedheap if it contains a reference type or if the type is boxed (we’ll cover boxing later in thischapter in the “Boxing” section)
Reference type: A reference type is defined in VB using the Class keyword It is called a reference type, because a reference type variable actually contains a reference to the object
on the managed heap instead of the object itself
Value Types
Value types typically reside in the memory stack and are commonly used when you need to
represent data that is generally small in its memory footprint Value types are efficient, and
when a value type variable goes out of scope, it’s immediately removed from the stack Not
surprisingly, value types are passed by value by default
The most common value types are the built-in data types such an Integer, Boolean, andDouble When you create a value type during the flow of execution, the value is created on the
stack, as shown in this code snippet:
Dim TheAnswer As Integer = 42
Console.WriteLine(TheAnswer.ToString)
Not only is the TheAnswer instance created on the stack, but if it’s passed to a method, themethod receives a copy of the value You can define user-defined value types in VB by using
the Structure keyword, as shown in the following snippet User-defined value types behave in
the same way that the built-in value types do:
Public Structure Coordinate 'This is a value type
Dim x As IntegerDim y As IntegerEnd Structure
Values can live on the managed heap, but not by themselves One way this can happen is
if a reference type contains a value type Even though a value type inside of an object lives on
the managed heap, it still behaves the same as a value type on the stack when it comes to
passing it into a method; that is, the method will receive a copy by default Any changes
made to the value instance are only local changes to the copy unless the value was passed
by reference The following code illustrates these concepts:
Module Module1
Public Structure Coordinate 'this is a value typeDim x As Integer
Dim y As IntegerEnd StructurePublic Class EntryPoint 'this is a reference type
Trang 11Public Function AttemptToModifyCoord(ByVal Coord As Coordinate) As BooleanCoord.x = 1
Coord.y = 3Return TrueEnd FunctionPublic Function ModifyCoord(ByRef Coord As Coordinate) As BooleanCoord.x = 10
Coord.y = 10Return TrueEnd FunctionEnd ClassSub Main()Dim Location As New CoordinateDim EP As New EntryPointLocation.x = 50
Location.y = 50EP.AttemptToModifyCoord(Location)System.Console.WriteLine("( {0}, {1} )", Location.x, Location.y)EP.ModifyCoord(Location)
System.Console.WriteLine("( {0}, {1} )", Location.x, Location.y)End Sub
End Module
In the Main method, the call to AttemptToModifyCoord actually does nothing to the Location.x and Location.y values This is because in the AttemptToModifyCoord method, theLocation parameter is passed by value and the method modifies a local copy of the structurethat was made when the method was called On the contrary, the Location parameter ispassed by reference to the ModifyCoord method Thus, any changes made in the ModifyCoordmethod are actually made on the Location value in the calling scope The output from theexample is as follows:
Trang 12customer types throughout your code, you can create an Enum and map the customer type ID
to a name like this:
Enum CustomerType As Integer
Individual = 1Corporate = 2HomeBusiness = 3Federal = 4End Enum
Note that the values don’t have to be in any sequential order Each constant that’s defined
in the enumeration must be defined with a value within the range of the underlying type If a
value is not specified for an enumeration constant, it takes the default value of 0 (if it’s the first
constant in the enumeration) or the value of the previous constant plus 1 This example is an
enumeration based upon a Long:
Enum Color As Long
RedGreen = 50BlueEnd Enum
In this example, if you had left off the Long keyword after the Color type identifier, theenumeration would have been of type Integer In this Enum, the value for Red is 0, the value
for Green is 50, and the value for Blue is 51 To use this enumeration, write the following:
Module Module1
Enum Color As LongRed
Green = 50BlueEnd EnumSub Main()Dim SystemColor As Color = Color.RedSystem.Console.WriteLine("Color is {0}", SystemColor.ToString)End Sub
End Module
If you compile and run this code, you’ll see that the output saysColor is Red
and it actually uses the name of the enumeration rather than the ordinal value 0 This magic is
done by the System.Enum type’s implementation of the ToString method, which returns the
color’s name
Trang 13■ Note The underlying type of the Enummust be an integral type that is one of the following:Byte,SByte,Short,UShort,Integer,UInteger,Long, or ULong.
When referring to Enum members, you typically precede the member name with the Enumname However, if you use the Imports statement with your Enum, you can then refer to theEnum members without their fully qualified names, like this:
initial-a different locinitial-ation in memory, initial-and the GC ensures thinitial-at vinitial-ariinitial-ables thinitial-at reference those objectsare updated
Reference types can also be initialized by assignment from another variable of a ble type as in the following code snippet, which creates two reference type variables:
compati-Public Class Coordinate
Dim x As IntegerDim y As IntegerEnd Class
…
Dim Point1 As Coordinate = New Coordinate
Dim Point2 As Coordinate = Point1
In the example, the value of Point1 and Point2 is a pointer to the Coordinate object cated on the heap If you passed Point1 into a function that updated x and y, you would seethose changes in Point2 as well
allo-■ Note Conventionally, the term object refers to an instance of a reference type, and the term value refers to
an instance of a value type Regardless of what you call them, all instances of any type derive from typeObject
In the managed environment of the CLR, the GC automatically handles all agement tasks, including the creation and destruction of objects This frees you from having toworry about explicitly deleting objects and minimizes memory leaks At any point in time, the
memory-man-GC determines how many references exist to a particular object on the heap If it determinesthere are none, it starts the process of destroying the object on the heap The previous code
Trang 14snippet contains two references to the same object The first one, Point1, is initialized by
cre-ating a new Coordinate object The second one, Point2, is initialized from Point1 The GC
won’t collect the Coordinate object on the heap until both of these references are outside any
usable scope Table 3-2 provides a summary of the differences between value types and
refer-ence types
Table 3-2.Comparison of Value Types and Reference Types
Represents simple values Represents more complex data structures
Declared using a Dim, Private,or Publicstatement Declared calling a class constructor
Initialized to 0or empty value by default Initialized to Nothingby default
Must always have a value Can have Nothingas a value
By default, passed by value By default, passed by reference
Value contains an actual value Value is a pointer to an object in memory
When passed as a parameter
A copy of the value is made A copy of the reference to the memory
location is made
Garbage Collection
Removed from the stack by the Destructors are called by the GC,
GC when it goes out of scope and the object is removed from the heap
by the GC when it goes out of scope
Type Conversion
Now that you have a good understanding of types in the NET world, let’s take a look at
con-verting instances of one type to another In some cases, this conversion is done implicitly by
the compiler when the value being converted won’t lose any precision or magnitude As you
saw in the discussion of Option Strict, this is known as a widening conversion In the case of
the following ComputAvg function, you can see that the function takes Integer parameters, but
when you pass in parameters of type Short, there’s no compiler error The compiler
automati-cally converts Param1 and Param2 to integers because there’s no danger that the value of a Short
(with a maximum value of 32,767) will be too large to fit in an Integer (with a maximum value
of 2,147,483,647):
Function ComputeAvg(ByVal Param1 As Integer, ByVal Param2 As Integer) As Double
ComputeAvg = (Param1 + Param2) / 2End Function
Dim Param1 As Short = 108
Dim Param2 As Short = 123
ComputeAvg(Param1, Param1)
Trang 15■ Note In Visual Studio 2005, the Option Strictsetting defaults to Off, but I recommend settingOption Strictto Onat the project level This ensures that you find any implicit data conversion errors atcompile time, and any narrowing data type conversions will require explicit conversion.
In cases where precision could be lost, an explicit conversion is required In VB, you havetwo options when performing an explicit conversion: you can use the VB conversion functionssuch as CStr or the System.Convert class functions such as Convert.ToString Table 3-3 liststhe functions available for explicit conversions
Table 3-3.Data Type Conversion Functions
VB Function Convert Function Description
array of Unicode characters
value
precision floating point value (Double)
value
value
precision floating point value (Single)
integer value (UInteger)
long value (ULong)
short value (UShort)
Trang 16Casting variables with either of these methods is pretty straightforward, as this code snippet shows:
Dim StringValue As String = "123"
Dim IntegerValue As Integer
IntegerValue = CInt(StringValue)
Deciding whether to use the conversion functions or the Convert class methods is strictly
a matter of style The Convert class makes code more consistent with data type conversions in
C#, which doesn’t have functions such as CStr The Convert class is found in the System
name-space, and the methods are called like this:
Dim StringValue As String = "123"
Dim IntegerValue As Integer
IntegerValue = Convert.ToInt32(StringValue)
Note that if the conversion causes a loss in magnitude, it’s possible that the conversionmay throw an exception at run time For example, if you tried to convert the string
"746475959658567" to an Integer, you would receive an overflow error because that value
exceeds the maximum value that an integer can contain
CType
You’ve seen how to convert value types in VB, but another common need is to convert
refer-ence types from one type to another A base class can be implicitly cast to a derived type,
because the derived type inherits from the base class However, a derived class must be
explic-itly cast to a base type using the CType function Essentially, CType converts the specified
expression to the specified data type, object, structure, class, or interface, and the syntax is as
follows:
CType(expression, typename)
In examining how to cast reference types, assume you have a Coordinate class and aGraphCoordinate class that inherits from and extends the Coordinate class You also have a
PrintCoordinates function that sends the x and y values to the console:
Public Class Coordinate
Public x As IntegerPublic y As IntegerEnd Class
Public Class GraphCoordinate
Inherits CoordinatePublic PointDesc As StringEnd Class
Trang 17Public Function PrintCoordinates(ByVal Coord As Coordinate) As Boolean
System.Console.WriteLine("( {0}, {1} )", Coord.x, Coord.y)Return True
End Function
As we said before, a base class can always be cast to a derived type Therefore, it’s possible
to implicitly cast any value to an Object because all types derive from Object The followingcode snippet won’t cause any errors:
Dim Coord As New Coordinate
Coord.x = 10
Coord.y = 50
Dim oCoord As Object = New Coordinate
Now let’s define the GraphCoordinate instance and then attempt to call the PrintCoordinates function:
Dim GraphCoord As New GraphCoordinate
Option Strict On, the third call results in a compiler error, disallowing the implicit conversion
of oCoord to the Coordinate class In order to pass oCoord as a parameter, you must “cast itdown” to the Coordinate type like this:
PrintCoordinates(CType(oCoord, Coordinate))
Another keyword related to reference type conversion is TypeOf Use TypeOf before using CType to determine if you can successfully convert the object Prior to calling the PrintCoordinates method, you could check the type of the oCoord variable and then call the method:
If TypeOf (oCoord) Is Coordinate Then
PrintCoordinates(CType(oCoord, Coordinate))End If
DirectCast and TryCast
New to the latest version of VB are two keywords related to casting reference types: DirectCastand TryCast The DirectCast function is used to cast reference types just like CType and has asimilar syntax:
DirectCast(expression, Type)
Trang 18However, DirectCast offers better performance because it directly attempts to convert thespecified type, and if it can’t, it throws an exception The command var = CType("123",
Integer) attempts to convert "123" even though it’s a string, and this statement succeeds
because VB will implicitly cast "123" to an Integer But the command var =
Direct-Cast("123", Integer) will fail because the compiler won’t try any implicit conversions and
attempts to directly convert a string to an Integer It’s recommended to use DirectCast when
you know a reference type conversion will work and you need the extra performance benefit
Another difference between CType and DirectCast is that you can only use DirectCast on
types that have an inheritance relationship Therefore, you can’t use DirectCast on value
types, including structures
The TryCast function has the same syntax as DirectCast and performs the same referencetype conversion However, if the cast fails, the function returns Nothing instead of throwing an
error So instead of handling errors from CType or DirectCast, you can use TryCast and check
for Nothing In this code snippet, TryCast attempts to convert reference type x to a type of
EntryPoint This conversion would normally cause an exception, but with TryCast, you simply
check for the result of the conversion:
Dim y As Object = TryCast(x, EntryPoint)
Another common type of conversion is a boxing conversion Boxing is required when a value
type must be assigned to a variable as a reference type To accomplish this type of conversion,
simply declare an object and set its value to that of the value type variable When you do this,
an object is allocated dynamically on the heap that contains the value of the value type
Chapter 4 covers boxing in VB extensively The following code demonstrates boxing:
Module Module1
Sub Main()Dim EmployeeID As Integer = 303Dim BoxedID As Object = EmployeeIDDim UnboxedID As Integer = CInt(BoxedID)EmployeeID = 404
System.Console.WriteLine(EmployeeID.ToString())System.Console.WriteLine(UnboxedID.ToString())End Sub
Trang 19is bridged between the value type and the reference type worlds within the CLR The BoxedIDobject actually contains a copy of the EmployeeID value This point is demonstrated in thesnippet when the original EmployeeID value is printed after the boxing operation Before print-ing out the values, you unbox the value and copy the value contained in the object on theheap back into another Integer on the stack Unboxing is the opposite action to boxing and isthe process of converting the reference type variable back to a value type variable on the stack.
Reference Type Operators
Although we’ll look at the VB operators in-depth in Chapter 4, there are some operators thatare helpful specifically when working with reference types Given the fact that explicit conver-sions can fail and throw exceptions, times arise when you want to test the type of a variablefirst instead of performing a cast and seeing whether or not it fails The Is operator in con-junction with the TypeOf keyword returns a Boolean that determines if you can convert thegiven expression to the given type as either a reference conversion or a boxing or unboxingoperation For example, consider the following code:
Public Class BaseType
Public x As IntegerPublic y As IntegerEnd Class
Public Class DerivedType
Inherits BaseTypePublic DT1 As LongPublic Description As StringEnd Class
Module Module1
Sub Main()Dim DerivedObj As DerivedType = New DerivedType()Dim BaseObj1 As BaseType = New BaseType()
Dim BaseObj2 = DerivedObj
If TypeOf BaseObj2 Is DerivedType ThenConsole.WriteLine("BaseObj2 {0} DerivedType", "is")Else
Console.WriteLine("BaseObj2 {0} DerivedType", "isnot")End If
If TypeOf BaseObj1 Is DerivedType ThenConsole.WriteLine("BaseObj1 {0} DerivedType", "is")Else
Console.WriteLine("BaseObj1 {0} DerivedType", "isnot")End If
If TypeOf DerivedObj Is BaseType Then
Trang 20Console.WriteLine("DerivedObj {0} BaseType", "is")Else
Console.WriteLine("DerivedObj {0} BaseType", "isnot")End If
Dim j As Integer = 123Dim Boxed As Object = jDim Obj As Object = New Object()
If TypeOf Boxed Is Integer ThenConsole.WriteLine("Boxed {0} Integer", "is")Else
Console.WriteLine("Boxed {0} Integer", "isnot")End If
If TypeOf Obj Is Integer ThenConsole.WriteLine("Obj {0} Integer", "is")Else
Console.WriteLine("Obj {0} Integer", "isnot")End If
If TypeOf Boxed Is ValueType ThenConsole.WriteLine("Boxed {0} System.ValueType", "is")Else
Console.WriteLine("Boxed {0} System.ValueType", "isnot")End If
End SubEnd Module
The output from this code is
Two related operators that are useful when working with reference types are Is and IsNot
The syntax for these operators looks like this:
BooleanResult = Object1 Is Object2
These two operators return a Boolean value after comparing the first object to see if itrefers to the same object as the second Note that the Is/IsNot operators only consider
Trang 21reference types, and VB will generate a compiler error if you try to use Is/IsNot with valuetypes Here’s a code example using the Is operator:
Dim ObjectA As New Object
Dim ObjectB As New Object
Dim ObjectC As New Object
Dim ObjectD As New Object
Dim IsObject As Boolean
ObjectA = ObjectC
ObjectB = ObjectC
IsObject = ObjectA Is ObjectC
IsObject = ObjectB Is ObjectC
IsObject = ObjectB Is ObjectA
IsObject = ObjectC Is ObjectD
The first three comparisons result in True because ObjectA and ObjectB both refer toObjectC The third comparison is the most interesting because even though ObjectA andObjectB have no relationship to each other through direct assignment, they both refer toObjectC and therefore are the same as each other The final comparison results in Falsebecause ObjectD is not assigned anywhere
Namespaces
Namespaces are used to organize your types within an assembly and help you avoid namingcollisions between your identifiers Using namespaces, you define all of your types such thattheir identifiers are qualified by the namespace that they belong to You’ve already seen name-spaces in action in many of the examples so far For example, in the Hello World! examplefrom Chapter 1, you saw the use of the Console class, which lives in the NET Framework ClassLibrary’s System namespace and whose fully qualified name is System.Console It’s a goodpractice to organize your components with namespaces, and the general recommendation is
to use some sort of identifier such as your organization’s name as the top-level namespaceand then more specific library identifiers as nested namespaces
Namespaces provide an excellent mechanism for making your types more discoverable,especially if you’re designing libraries meant for consumption by others For example, you cancreate a general namespace such as MyCompany.Widgets where you put the most commonlyused types of widgets Then you can create a MyCompany.Widgets.Advanced namespace whereyou place all of the less commonly used, advanced types Sure, you could place them all in onenamespace However, it’s much easier for consumers of your libraries to see the types logicallyarranged with the commonly used ones separated from the less commonly used types
■ Note Within a namespace, you can define “container” items such as modules, interfaces, classes, gates, enumerations, structures, and nested namespaces You cannot have properties, procedures, variables,
dele-or events within a namespace