Tải bản đầy đủ (.pdf) (109 trang)

Pro VB 2005 and the .NET 2.0 Platform Second Edition phần 5 pdf

Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (1.97 MB, 109 trang )

CHAPTER 13 ■ INTRODUCING .NET ASSEMBLIES388
To rectify the situation, create a new configuration file named Vb2005CarClient.exe.config
and save it in the same folder containing the Vb2005CarClient.exe application, which in this exam-
ple would be C:\MyApp. Open this file and enter the following content exactly as shown (be aware
that XML is case sensitive!):
<configuration>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<probing privatePath="MyLibraries"/>
</assemblyBinding>
</runtime>
</configuration>
.NET *.config files always open with a root element named <configuration>. The nested <runtime>
element may specify an <assemblyBinding> element, which nests a further element named <probing>.
The privatePath attribute is the key point in this example, as it is used to specify the subdirectories
relative to the application directory where the CLR should probe.
Do note that the <probing> element does not specify which assembly is located under a given
subdirectory. In other words, you cannot say, “CarLibrary is located under the MyLibraries subdirec-
tory, but MathUtils is located under the Bin subdirectory.” The <probing> element simply instructs
the CLR to investigate all specified subdirectories for the requested assembly until the first match is
encountered.
■Note Be very aware that the privatePath attribute
cannot be used
to specify an absolute (C:\SomeFolder\
SomeSubFolder) or relative ( \SomeFolder\AnotherFolder) path! If you wish to specify a directory outside the
client’s application directory, you will need to make use of a completely different XML element named
<codeBase>,
described later in the chapter.
Multiple subdirectories can be assigned to the privatePath attribute using a semicolon-delimited
list. You have no need to do so at this time, but here is an example that informs the CLR to consult
the MyLibraries and MyLibraries\Tests client subdirectories:


<probing privatePath="MyLibraries;MyLibraries\Tests"/>
Once you’ve finished creating Vb2005CarClient.exe.config, run the client by double-clicking
the executable in Windows Explorer. You should find that Vb2005CarClient.exe executes without
a hitch (if this is not the case, double-check it for typos in your XML document).
Next, for testing purposes, change the name of your configuration file (in one way or another)
and attempt to run the program once again. The client application should now fail. Remember that
*.config files must be prefixed with the same name as the related client application. By way of a final
test, open your configuration file for editing and capitalize any of the XML elements. Once the file is
saved, your client should fail to run once again (as XML is case sensitive).
Configuration Files and Visual Studio 2005
While you are always able to create XML configuration files by hand using your text editor of choice,
Visual Studio 2005 allows you create a configuration file during the development of the client program.
To illustrate, load the Vb2005CarClient (or CSharpCarClient) solution into Visual Studio 2005 and
insert a new Application Configuration File item (see Figure 13-13) using the Project ➤ Add New
Item menu selection. Before you click the OK button, take note that the file is named app.config
(don’t rename it!). If you look in the Solution Explorer window, you will now find app.config has
been inserted into your current project.
5785ch13.qxd 3/31/06 10:56 AM Page 388
CHAPTER 13 ■ INTRODUCING .NET ASSEMBLIES 389
At this point, you are free to enter the necessary XML elements for the client you happen to be
creating. Now, here is the cool thing. Each time you compile your project, Visual Studio 2005 will
automatically copy the data in app.config to the \bin\Debug directory using the proper naming
convention (such as Vb2005CarClient.exe.config). However, this behavior will happen only if your
configuration file is indeed named app.config.
Using this approach, all you need to do is maintain app.config, and Visual Studio 2005 will
ensure your application directory contains the latest and greatest content (even if you happen to
rename your project).
■Note For better or for worse, when you insert a new app.config file into a VB 2005 project, the IDE will add
a good deal of data within an element named
<system.diagnostics>, which has nothing to do with assembly

binding. For the remainder of this chapter, I will assume that you will delete this unnecessary XML data and author
the XML elements as shown in the remaining code examples.
Introducing the .NET Framework 2.0 Configuration Utility
Although authoring a *.config file by hand is not too traumatic, the .NET Framework 2.0 SDK does
ship with a tool that allows you to build XML configuration files using a friendly GUI editor. You can
find the .NET Framework 2.0 Configuration utility under the Administrative folder of your Control
Panel. Once you launch this tool, you will find a number of configuration options, as shown in
Figure 13-14.
Figure 13-13. The Visual Studio 2005 app.config file
5785ch13.qxd 3/31/06 10:56 AM Page 389
CHAPTER 13 ■ INTRODUCING .NET ASSEMBLIES390
To build a client *.config file using this utility, your first step is to add the application to con-
figure by right-clicking the Applications node and selecting Add. In the resulting dialog box, you
may find the application you wish to configure, provided that you have executed it using Windows
Explorer. If this is not the case, click the Other button and navigate to the location of the client pro-
gram you wish to configure. For this example, select the CSharpCarClient.exe application created
earlier in this chapter (look under the Bin folder). Once you have done so, you will now find a new
subnode, as shown in Figure 13-15.
If you right-click the CSharpCarClient node and activate the Properties page, you will notice
a text field located at the bottom of the dialog box where you can enter the values to be assigned to
the privatePath attribute. Just for testing purposes, enter a subdirectory named MyLibraries (see
Figure 13-16).
Figure 13-14. The .NET Framework 2.0 Configuration utility
Figure 13-15. Preparing to configure CSharpCarClient.exe
5785ch13.qxd 3/31/06 10:56 AM Page 390
CHAPTER 13 ■ INTRODUCING .NET ASSEMBLIES 391
Once you click the OK button, you can examine the CSharpCarClient\Bin\Debug directory and
find that a new *.config file has been updated with the correct <probing> element.
■Note As you may guess, you can copy the XML content generated by the .NET Framework 2.0 Configuration
utility into a Visual Studio 2005

app.config file for further editing. Using this approach, you can certainly decrease
your typing burden by allowing the tool to generate the initial content.
Understanding Shared Assemblies
Now that you understand how to deploy and configure a private assembly, you can begin to exam-
ine the role of a shared assembly. Like a private assembly, a shared assembly is a collection of types
and (optional) resources. The most obvious difference between shared and private assemblies is the
fact that a single copy of a shared assembly can be used by several applications on a single machine.
Consider all the applications created in this text that required you to set a reference to System.
Windows.Forms.dll. If you were to look in the application directory of each of these clients, you
would not find a private copy of this .NET assembly. The reason is that System.Windows.Forms.dll
has been deployed as a shared assembly. Clearly, if you need to create a machine-wide class library,
this is the way to go.
As suggested in the previous paragraph, a shared assembly is not deployed within the same
directory as the application making use of it. Rather, shared assemblies are installed into the Global
Assembly Cache. The GAC is located under a subdirectory of your Windows directory named Assembly
(e.g., C:\WINDOWS\Assembly), as shown in Figure 13-17.
Figure 13-16. Configuring a private probing path graphically
5785ch13.qxd 3/31/06 10:56 AM Page 391
CHAPTER 13 ■ INTRODUCING .NET ASSEMBLIES392
■Note You cannot install executable assemblies (*.exe) into the GAC. Only assemblies that take the *.dll file
extension can be deployed as a shared assembly.
Understanding Strong Names
Before you can deploy an assembly to the GAC, you must assign it a strong name, which is used to
uniquely identify the publisher of a given .NET binary. Understand that a “publisher” could be an
individual programmer, a department within a given company, or an entire company at large.
In some ways, a strong name is the modern day .NET equivalent of the COM globally unique
identifier (GUID) identification scheme. If you have a COM background, you may recall that AppIDs
are GUIDs that identify a particular COM application. Unlike COM GUID values (which are nothing
more than 128-bit numbers), strong names are based (in part) on two cryptographically related keys
(termed the public key and the private key), which are much more unique and resistant to tampering

than a simple GUID.
Formally, a strong name is composed of a set of related data, much of which is specified using
assembly-level attributes:
• The friendly name of the assembly (which you recall is the name of the assembly minus the
file extension)
• The version number of the assembly (assigned using the <AssemblyVersion> attribute)
• The public key value (assigned using the <AssemblyKeyFile> attribute)
• An optional culture identity value for localization purposes (assigned using the
<AssemblyCulture> attribute)
• An embedded digital signature created using a hash of the assembly’s contents and the
private key value
To provide a strong name for an assembly, your first step is to generate public/private key data
using the .NET Framework 2.0 SDK’s sn.exe utility (which you’ll do momentarily). The sn.exe utility
responds by generating a file (typically ending with the *.snk [Strong Name Key] file extension) that
contains data for two distinct but mathematically related keys, the “public” key and the “private”
key. Once the VB 2005 compiler is made aware of the location for your *.snk file, it will record the
full public key value in the assembly manifest using the .publickey at the time of compilation.
Figure 13-17. The GAC
5785ch13.qxd 3/31/06 10:56 AM Page 392
CHAPTER 13 ■ INTRODUCING .NET ASSEMBLIES 393
The VB 2005 compiler will also generate a hash code based on the contents of the entire assembly
(CIL code, metadata, and so forth). As you recall from Chapter 6, a hash code is a numerical value
that is unique for a fixed input. Thus, if you modify any aspect of a .NET assembly (even a single
character in a string literal), the compiler yields a unique hash code. This hash code is combined
with the private key data within the *.snk file to yield a digital signature embedded within the assem-
bly’s CLR header data. The process of strongly naming an assembly is illustrated in Figure 13-18.
Understand that the actual private key data is not listed anywhere within the manifest, but is
used only to digitally sign the contents of the assembly (in conjunction with the generated hash
code). Again, the whole idea of making use of public/private key data is to ensure that no two com-
panies, departments, or individuals have the same identity in the .NET universe. In any case, once

the process of assigning a strong name is complete, the assembly may be installed into the GAC.
■Note Strong names also provide a level of protection against potential evildoers tampering with your assem-
bly’s contents. Given this point, it is considered a .NET best practice to strongly name every assembly regardless of
whether it is deployed to the GAC.
Strongly Naming CarLibrary.dll Using sn.exe
Let’s walk through the process of assigning a strong name to the CarLibrary assembly created earlier
in this chapter (go ahead and open up that project using your IDE of choice). The first order of busi-
ness is to generate the required key data using the sn.exe utility. Although this tool has numerous
command-line options, all you need to concern yourself with for the moment is the -k flag, which
instructs the tool to generate a new file containing the public/private key information. Create a new
folder on your C drive named MyTestKeyPair and change to that directory using the .NET Command
Prompt. Now, issue the following command to generate a file named MyTestKeyPair.snk:
sn -k MyTestKeyPair.snk
Now that you have your key data, you need to inform the VB 2005 compiler exactly where
MyTestKeyPair.snk is located. When you create any new VB 2005 project workspace using Visual
Figure 13-18. At compile time, a digital signature is generated and embedded into the assembly based
in part on public and private key data.
5785ch13.qxd 3/31/06 10:56 AM Page 393
CHAPTER 13 ■ INTRODUCING .NET ASSEMBLIES394
Studio 2005, you will receive a project file (located under the My Project node of Solution Explorer)
named AssemblyInfo.vb. By default, you cannot see this file; however, if you click the Show All Files
button on the Solution Explorer, you will see this is the case, as shown in Figure 13-19.
This file contains a number of attributes that describe the assembly itself. The AssemblyKeyFile
assembly-level attribute can be used to inform the compiler of the location of a valid *.snk file.
Simply specify the path as a string parameter, for example:
<Assembly: AssemblyKeyFile("C:\MyTestKeyPair\MyTestKeyPair.snk")>
In the AssemblyInfo.vb file, you will find another attribute named <AssemblyVersion>. Initially
the value is set to 1.0.0.0. Recall that a .NET version number is composed of these four parts:
(<major>.<minor>.<build>.<revision>).
<Assembly: AssemblyVersion("1.0.0.0")>

At this point, the VB 2005 compiler has all the information needed to generate strong name
data (as you are not specifying a unique culture value via the <AssemblyCulture> attribute, you
“inherit” the culture of your current machine). Compile your CarLibrary code library and open the
manifest using ildasm.exe. You will now see a new .publickey tag is used to document the full pub-
lic key information, while the .ver token records the version specified via the <AssemblyVersion>
attribute, as shown in Figure 13-20.
Figure 13-19. The hidden AssemblyInfo.vb file
Figure 13-20. A strongly named assembly records the public key in the manifest.
5785ch13.qxd 3/31/06 10:56 AM Page 394
CHAPTER 13 ■ INTRODUCING .NET ASSEMBLIES 395
Assigning Strong Names Using Visual Studio 2005
Before you deploy CarLibrary.dll to the GAC, let me point out that Visual Studio 2005 allows you to
specify the location of your *.snk file using the project’s Properties page (in fact, this is now consid-
ered the preferred approach). To do so, select the Signing node, supply the path to the *.snk file, and
select the “Sign the assembly” check box (see Figure 13-21).
Installing/Removing Shared Assemblies to/from the GAC
The final step is to install the (now strongly named) CarLibrary.dll into the GAC. The simplest way
to install a shared assembly into the GAC is to drag and drop the assembly to C:\WINDOWS\Assem-
bly using Windows Explorer, which is ideal for a quick test (know that copy/paste operations will
not work when deploying to the GAC).
In addition, the .NET Framework 2.0 SDK provides a command-line utility named gacutil.exe
that allows you to examine and modify the contents of the GAC. Table 13-1 documents some relevant
options of gacutil.exe (specify the /? flag to see each option).
Table 13-1. Various Options of gacutil.exe
Option Meaning in Life
/i Installs a strongly named assembly into the GAC
/u Uninstalls an assembly from the GAC
/l Displays the assemblies (or a specific assembly) in the GAC
Using either technique, deploy CarLibrary.dll to the GAC. Once you’ve finished, you should
see your library present and accounted for, as shown in Figure 13-22.

Figure 13-21. Specifying an *.snk file via the Properties page
5785ch13.qxd 3/31/06 10:56 AM Page 395
CHAPTER 13 ■ INTRODUCING .NET ASSEMBLIES396
■Note You may right-click any assembly icon to pull up its Properties page, and you may also uninstall a specific
version of an assembly altogether from the right-click context menu (the GUI equivalent of supplying the
/u flag to
gacutil.exe).
Consuming a Shared Assembly
When you are building applications that make use of a shared assembly, the only difference from
consuming a private assembly is in how you reference the library using Visual Studio 2005. In reality,
there is no difference as far as the tool is concerned (you still make use of the Add Reference dialog
box). What you must understand is that this dialog box will not allow you to reference the assembly
by browsing to the Assembly folder. Any efforts to do so will be in vain, as you cannot reference the
assembly you have highlighted. Rather, you will need to browse to the \bin\Debug directory of
the original project via the Browse tab, which is shown in Figure 13-23.
Figure 13-22. The strongly named, shared CarLibrary (version 1.0.0.0)
Figure 13-23. Correct! You must reference shared assemblies by navigating to the project’s \bin\Debug
directory using Visual Studio 2005.
5785ch13.qxd 3/31/06 10:56 AM Page 396
CHAPTER 13 ■ INTRODUCING .NET ASSEMBLIES 397
This (somewhat annoying) fact aside, create a new VB 2005 console application named
SharedCarLibClient and exercise your types as you wish:
Imports CarLibrary
Module Program
Sub Main()
Dim mycar As New SportsCar()
mycar.TurboBoost()
Console.ReadLine()
End Sub
End Module

Once you have compiled your client application, navigate to the directory that contains
SharedCarLibClient.exe using Windows Explorer and notice that Visual Studio 2005 has not copied
CarLibrary.dll to the client’s application directory. When you reference an assembly whose manifest
contains a .publickey value, Visual Studio 2005 assumes the strongly named assembly will most
likely be deployed in the GAC, and therefore does not bother to copy the binary.
Exploring the Manifest of SharedCarLibClient
Recall that when you generate a strong name for an assembly, the entire public key is recorded in
the assembly manifest. On a related note, when a client references a strongly named assembly, its
manifest records a condensed hash-value of the full public key, denoted by the .publickeytoken tag.
If you were to open the manifest of SharedCarLibClient.exe using ildasm.exe, you would find the
following:
.assembly extern CarLibrary
{
.publickeytoken = (21 9E F3 80 C9 34 8A 38)
.ver 1:0:0:0
}
If you compare the value of the public key token recorded in the client manifest with the public
key token value shown in the GAC, you will find a dead-on match. Recall that a public key represents
one aspect of the strongly named assembly’s identity. Given this, the CLR will only load version 1.0.0.0
of an assembly named CarLibrary that has a public key that can be hashed down to the value
219EF380C9348A38. If the CLR does not find an assembly meeting this description in the GAC (and
cannot find a private assembly named CarLibrary in the client’s directory), a FileNotFound exception
is thrown.
■Source Code The SharedCarLibClient application can be found under the Chapter 13 subdirectory.
Configuring Shared Assemblies
Like a private assembly, shared assemblies can be configured using a client *.config file. Of
course, because shared assemblies are found in a well-known location (the GAC), you will not
specify a <privatePath> element as you did for private assemblies (although if the client is using
both shared and private assemblies, the <privatePath> element may still exist in the *.config file).
You can use application configuration files in conjunction with shared assemblies whenever

you wish to instruct the CLR to bind to a different version of a specific assembly, effectively bypassing
the value recorded in the client’s manifest. This can be useful for a number of reasons. For example,
imagine that you have shipped version 1.0.0.0 of an assembly and discover a major bug sometime
5785ch13.qxd 3/31/06 10:56 AM Page 397
CHAPTER 13 ■ INTRODUCING .NET ASSEMBLIES398
after the fact. One corrective action would be to rebuild the client application to reference the cor-
rect version of the bug-free assembly (say, 1.1.0.0) and redistribute the updated client and new library
to each and every target machine.
Another option is to ship the new code library and a *.config file that automatically instructs
the runtime to bind to the new (bug-free) version. As long as the new version has been installed into
the GAC, the original client runs without recompilation, redistribution, or fear of having to update
your resume.
Here’s another example: you have shipped the first version of a bug-free assembly (1.0.0.0), and
after a month or two, you add new functionality to the assembly in question to yield version 2.0.0.0.
Obviously, existing client applications that were compiled against version 1.0.0.0 have no clue about
these new types, given that their code base makes no reference to them.
New client applications, however, wish to make reference to the new functionality found in
version 2.0.0.0. Under .NET, you are free to ship version 2.0.0.0 to the target machines, and have ver-
sion 2.0.0.0 run alongside the older version 1.0.0.0. If necessary, existing clients can be dynamically
redirected to load version 2.0.0.0 (to gain access to the implementation refinements), using an
application configuration file without needing to recompile and redeploy the client application.
Freezing the Current Shared Assembly
To illustrate how to dynamically bind to a specific version of a shared assembly, open Windows
Explorer and copy the current version of CarLibrary (1.0.0.0) into a distinct subdirectory (I called mine
“Version 1.0.0.0”) off the project root to symbolize the freezing of this version (see Figure 13-24).
Building Shared Assembly Version 2.0.0.0
Now, update your CarLibrary project to define a new Enum named MusicMedia that defines four pos-
sible musical devices:
' Holds source of music.
Public Enum MusicMedia

musicCd
musicTape
musicRadio
musicMp3
End Enum
Figure 13-24. Freezing the current version of CarLibrary.dll
5785ch13.qxd 3/31/06 10:56 AM Page 398
CHAPTER 13 ■ INTRODUCING .NET ASSEMBLIES 399
As well, add a new public method to the Car type that allows the caller to turn on one of the
given media players (be sure to import the System.Windows.Forms namespace):
Public MustInherit Class Car

Public Sub TurnOnRadio(ByVal musicOn As Boolean, ByVal mm As MusicMedia)
If musicOn Then
MessageBox.Show(String.Format("Jamming {0}", mm))
Else
MessageBox.Show("Quiet time ")
End If
End Sub

End Class
Update the constructors of the Car class to display a MessageBox that verifies you are indeed
using CarLibrary 2.0.0.0:
Public MustInherit Class Car

Public Sub New()
MessageBox.Show("Car 2.0.0.0")
End Sub
Public Sub New(ByVal name As String, ByVal max As Short, ByVal curr As Short)
MessageBox.Show("Car 2.0.0.0")

name = name
max_speed = max
speed = curr
End Sub

End Class
Finally, before you recompile, be sure to update this version of this assembly to 2.0.0.0 by
updating the value passed to the <AssemblyVersion> and <AssemblyFileVersion> attributes within
the AssemblyInfo.vb file:
' CarLibrary version 2.0.0.0 (now with music!)
<Assembly: AssemblyFileVersion("2.0.0.0")>
<Assembly: AssemblyVersion("2.0.0.0")>
If you look in your project’s \Bin\Debug folder, you’ll see that you have a new version of this
assembly (2.0.0.0), while version 1.0.0.0 is safe in storage under the Version 1 subdirectory. Install
this new assembly into the GAC as described earlier in this chapter. Notice that you now have two
versions of the same assembly, as shown in Figure 13-25.
Figure 13-25. Side-by-side execution
5785ch13.qxd 3/31/06 10:56 AM Page 399
CHAPTER 13 ■ INTRODUCING .NET ASSEMBLIES400
If you were to run the current SharedCarLibClient.exe program by double-clicking the icon
using Windows Explorer, you should not see the “Car 2.0.0.0” message box appear, as the manifest is
specifically requesting version 1.0.0.0. How then can you instruct the CLR to bind to version 2.0.0.0?
Glad you asked.
Dynamically Redirecting to Specific Versions of a Shared Assembly
When you wish to inform the CLR to load a version of a shared assembly other than the version listed
in its manifest, you may build a *.config file that contains a <dependentAssembly> element. When
doing so, you will need to create an <assemblyIdentity> subelement that specifies the friendly name
of the assembly listed in the client manifest (CarLibrary, for this example) and an optional culture
attribute (which can be assigned an empty string or omitted altogether if you wish to specify the default
culture for the machine). Moreover, the <dependentAssembly> element will define a <bindingRedirect>

subelement to define the version currently in the manifest (via the oldVersion attribute) and the
version in the GAC to load instead (via the newVersion attribute).
Create a new configuration file in the application directory of SharedCarLibClient named
SharedCarLibClient.exe.config that contains the following XML data. Of course, the value of your
public key token will be different from what you see in the following code, and it can be obtained
either by examining the client manifest using ildasm.exe or via the GAC.
<configuration>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="CarLibrary"
publicKeyToken="219ef380c9348a38"/>
<bindingRedirect oldVersion= "1.0.0.0"
newVersion= "2.0.0.0"/>
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>
Now run the SharedCarLibClient.exe program. You should see the message that displays ver-
sion 2.0.0.0 has loaded. If you set the newVersion attribute to 1.0.0.0 (or if you simply deleted the
*.config file), you now see the message that version 1.0.0.0 has loaded, as the CLR found version
1.0.0.0 listed in the client’s manifest.
Multiple <dependentAssembly> elements can appear within a client’s configuration file. Although
you have no need to do so, assume that the manifest of SharedCarLibClient.exe also references
version 2.5.0.0 of an assembly named MathLibrary. If you wished to redirect to version 3.0.0.0 of
MathLibrary (in addition to version 2.0.0.0 of CarLibrary), the SharedCarLibClient.exe.config file
would look like the following:
<configuration>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">

<dependentAssembly>
<assemblyIdentity name="CarLibrary"
publicKeyToken="219ef380c9348a38"/>
<bindingRedirect oldVersion= "1.0.0.0"
newVersion= "2.0.0.0"/>
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="MathLibrary"
publicKeyToken="219ef380c9348a38"/>
<bindingRedirect oldVersion= "2.5.0.0"
5785ch13.qxd 3/31/06 10:56 AM Page 400
CHAPTER 13 ■ INTRODUCING .NET ASSEMBLIES 401
newVersion= "3.0.0.0"/>
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>
Revisiting the .NET Framework 2.0 Configuration Utility
As you would hope, you can generate shared assembly–centric *.config files using the graphical .NET
Framework 2.0 Configuration utility. Like the process of building a *.config file for private assemblies,
the first step is to reference the *.exe to configure. To illustrate, delete the SharedCarLibClient.exe.config
you just authored. Now, add a reference to SharedCarLibClient.exe by right-clicking the Applications
node. Once you do, expand the plus sign (+) icon and select the Configured Assemblies subnode. From
here, click the Configure an Assembly link on the right side of the utility.
At this point, you are presented with a dialog box that allows you to establish a <dependentAssembly>
element using a number of friendly UI elements. First, select the “Choose an assembly from the list
of assemblies this application uses” radio button (which simply means, “Show me the manifest!”)
and click the Choose Assembly button.
A dialog box now displays that shows you not only the assemblies specifically listed in the client
manifest, but also the assemblies referenced by these assemblies. For this example’s purposes, select

CarLibrary. When you click the Finish button, you will be shown a Properties page for this one small
aspect of the client’s manifest. Here, you can generate the <dependentAssembly> using the Binding
Policy tab.
Once you select the Binding Policy tab, you can set the oldVersion attribute (1.0.0.0) via the
Requested Version text field and the newVersion attribute (2.0.0.0) using the New Version text field.
Once you have committed the settings, you will find the following configuration file is generated
for you:
<?xml version="1.0"?>
<configuration>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="CarLibrary"
publicKeyToken="219ef380c9348a38"/>
<publisherPolicy apply="yes"/>
<bindingRedirect oldVersion="1.0.0.0" newVersion="2.0.0.0"/>
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>
Understanding Publisher Policy Assemblies
The next configuration issue you’ll examine is the role of publisher policy assemblies. As you’ve just
seen, *.config files can be constructed to bind to a specific version of a shared assembly, thereby
bypassing the version recorded in the client manifest. While this is all well and good, imagine you’re
an administrator who now needs to reconfigure all client applications on a given machine to rebind
to version 2.0.0.0 of the CarLibrary.dll assembly. Given the strict naming convention of a configu-
ration file, you would need to duplicate the same XML content in numerous locations (assuming
you are, in fact, aware of the locations of the executables using CarLibrary!). Clearly this would be
a maintenance nightmare.
5785ch13.qxd 3/31/06 10:56 AM Page 401

CHAPTER 13 ■ INTRODUCING .NET ASSEMBLIES402
Publisher policy allows the publisher of a given assembly (you, your department, your company,
or what have you) to ship a binary version of a *.config file that is installed into the GAC along with
the newest version of the associated assembly. The benefit of this approach is that client application
directories do not need to contain specific *.config files. Rather, the CLR will read the current manifest
and attempt to find the requested version in the GAC. However, if the CLR finds a publisher policy
assembly, it will read the embedded XML data and perform the requested redirection at the level of
the GAC.
Publisher policy assemblies are created at the command line using a .NET utility named al.exe
(the assembly linker). While this tool provides a large number of options, building a publisher policy
assembly requires you only to pass in the following input parameters:
• The location of the *.config or *.xml file containing the redirecting instructions
• The name of the resulting publisher policy assembly
• The location of the *.snk file used to sign the publisher policy assembly
• The version numbers to assign the publisher policy assembly being constructed
If you wish to build a publisher policy assembly that controls CarLibrary.dll, the command
set is as follows (which should be entered on a single line):
al /link: CarLibraryPolicy.xml /out:policy.1.0.CarLibrary.dll
/keyf:C:\ MyKey\ myKey.snk /v:1.0.0.0
Here, the XML content is contained within a file named CarLibraryPolicy.xml. The name of the
output file (which must be in the format policy.<major>.<minor>.assemblyToConfigure) is specified
using the obvious /out flag. In addition, note that the name of the file containing the public/private
key pair will also need to be supplied via the /keyf option. (Remember, publisher policy files are
deployed to the GAC, and therefore must have a strong name!)
Once the al.exe tool has executed, the result is a new assembly that can be placed into the
GAC to force all clients to bind to version 2.0.0.0 of CarLibrary.dll, without the use of a specific
client application configuration file.
Disabling Publisher Policy
Now, assume you (as a system administrator) have deployed a publisher policy assembly (and the
latest version of the related assembly) to a client machine’s GAC. As luck would have it, nine of the

ten affected applications rebind to version 2.0.0.0 without error. However, the remaining client
application (for whatever reason) blows up when accessing CarLibrary.dll 2.0.0.0 (as we all know,
it is next to impossible to build backward-compatible software that works 100 percent of the time).
In such a case, it is possible to build a configuration file for a specific troubled client that
instructs the CLR to ignore the presence of any publisher policy files installed in the GAC. The
remaining client applications that are happy to consume the newest .NET assembly will simply be
redirected via the installed publisher policy assembly. To disable publisher policy on a client-by-client
basis, author a (properly named) *.config file that makes use of the <publisherPolicy> element and
set the apply attribute to no. When you do so, the CLR will load the version of the assembly originally
listed in the client’s manifest.
<configuration>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<publisherPolicy apply="no" />
</assemblyBinding>
</runtime>
</configuration>
5785ch13.qxd 3/31/06 10:56 AM Page 402
CHAPTER 13 ■ INTRODUCING .NET ASSEMBLIES 403
Understanding the <codeBase> Element
Application configuration files can also specify code bases. The <codeBase> element can be used to
instruct the CLR to probe for dependent assemblies located at arbitrary locations (such as network
share points, or simply a local directory outside a client’s application directory).
■Note If the value assigned to a <codeBase> element is located on a remote machine, the assembly will be
downloaded on demand to a specific directory in the GAC termed the
download cache
. You can view the content of
your machine’s download cache by supplying the /ldl option to gacutil.exe.
Given what you have learned about deploying assemblies to the GAC, it should make sense that
assemblies loaded from a <codeBase> element will need to be assigned a strong name (after all, how

else could the CLR install remote assemblies to the GAC?).
■Note Technically speaking, the <codeBase> element can be used to probe for assemblies that do not have
a strong name. However, the assembly’s location must be relative to the client’s application directory (and thus is
little more than an alternative to the <privatePath> element).
Create a console application named CodeBaseClient, set a reference to CarLibrary.dll version
2.0.0.0, and update the initial file as follows:
Imports CarLibrary
Module Program
Sub Main()
Console.WriteLine("***** Fun with CodeBases *****")
Dim c As SportsCar = New SportsCar()
Console.WriteLine("Sports car has been allocated.")
Console.ReadLine()
End Sub
End Module
Given that CarLibrary.dll has been deployed to the GAC, you are able to run the program as is.
However, to illustrate the use of the <codeBase> element, create a new folder under your C drive
(perhaps C:\MyAsms) and place a copy of CarLibrary.dll version 2.0.0.0 into this directory.
Now, add an app.config file to the CodeBaseClient project (as explained earlier in this chapter)
and author the following XML content (remember that your .publickeytoken value will differ; consult
your GAC as required):
<configuration>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="SharedAssembly" publicKeyToken="219ef380c9348a38" />
<codeBase version="2.0.0.0" href="file:///C:\MyAsms\CarLibrary.dll" />
</dependentAssembly>
</assemblyBinding>
</runtime>

</configuration>
As you can see, the <codeBase> element is nested within the <assemblyIdentity> element, which
makes use of the name and publicKeyToken attributes to specify the friendly name as associated
publicKeyToken values. The <codeBase> element itself specifies the version and location (via the href
5785ch13.qxd 3/31/06 10:56 AM Page 403
CHAPTER 13 ■ INTRODUCING .NET ASSEMBLIES404
property) of the assembly to load. If you were to delete version 2.0.0.0 of CarLibrary.dll from the GAC,
this client would still run successfully, as the CLR is able to locate the external assembly under
C:\MyAsms.
However, if you were to delete the MyAsms directory from your machine, the client would now
fail. Clearly the <codeBase> elements (if present) take precedence over the investigation of the GAC.
■Note If you place assemblies at random locations on your development machine, you are in effect re-creating
the system registry (and the related DLL hell), given that if you move or rename the folder containing your binaries,
the current bind will fail. Given this point, use <codeBase> with caution.
The <codeBase> element can also be helpful when referencing assemblies located on
a remote networked machine. Assume you have permission to access a folder located at http://
www.IntertechTraining.com. To download the remote *.dll to the GAC’s download cache on your
location machine, you could update the <codeBase> element as follows:
<codeBase version="2.0.0.0"
href=" />
■Source Code The CodeBaseClient application can be found under the Chapter 13 subdirectory.
The System.Configuration Namespace
Currently, all of the *.config files shown in this chapter have made use of well-known XML elements
that are read by the CLR to resolve the location of external assemblies. In addition to these recognized
elements, it is perfectly permissible for a client configuration file to contain application-specific data
that has nothing to do with binding heuristics. Given this, it should come as no surprise that the .NET
Framework provides a namespace that allows you to programmatically read the data within a client
configuration file.
The System.Configuration namespace provides a small set of types you may use to read cus-
tom data from a client’s *.config file. These custom settings must be contained within the scope of

an <appSettings> element. The <appSettings> element contains any number of <add> elements that
define a key/value pair to be obtained programmatically.
For example, assume you have a *.config file for a console application named AppConfigReaderApp
that defines a database connection string and a point of data named timesToSayHello:
<configuration>
<appSettings>
<add key="appConStr"
value="server=localhost;uid='sa';pwd='';database=Cars" />
<add key="timesToSayHello" value="8" />
</appSettings>
</configuration>
Reading these values for use by the client application is as simple as calling the instance-level
GetValue() method of the System.Configuration.AppSettingsReader type. As shown in the follow-
ing code, the first parameter to GetValue() is the name of the key in the *.config file, whereas the
second parameter is the underlying type of the key (obtained via the VB 2005 GetType operator):
Imports System.Configuration
Module Program
Sub Main()
5785ch13.qxd 3/31/06 10:56 AM Page 404
CHAPTER 13 ■ INTRODUCING .NET ASSEMBLIES 405
Dim ar As AppSettingsReader = New AppSettingsReader
Console.WriteLine(ar.GetValue("appConStr", GetType(String)))
Dim numbOfTimes As Integer = CType(ar.GetValue("timesToSayHello", _
GetType(Integer)), Integer)
For i As Integer = 0 To numbOfTimes
Console.WriteLine("Yo!")
Next
Console.ReadLine()
End Sub
End Module

The AppSettingsReader class type does not provide a way to write application-specific data to
a *.config file. While this may seem like a limitation at first encounter, it actually makes good sense.
The whole idea of a *.config file is that it contains read-only data that is consulted by the CLR (or
possibly the AppSettingsReader type) after an application has already been deployed to a target
machine.
■Note During our examination of ADO.NET (Chapter 24), you will learn about the new <connectionStrings>
configuration element and new types within the System.Configuration namespace. These .NET 2.0–specific
items provide a standard manner to handle connection string data.
■Source Code The AppConfigReaderApp application can be found under the Chapter 13 subdirectory.
The Machine Configuration File
The configuration files you’ve examined in this chapter have a common theme: they apply only to
a specific application (that is why they have the same name as the launching application). In addition,
each .NET-aware machine has a file named machine.config that contains a vast number of configu-
ration details (many of which have nothing to do with resolving external assemblies) that control
how the .NET platform operates.
The .NET platform maintains a separate *.config file for each version of the framework installed
on the local machine. The machine.config file for .NET 2.0 can be found under the C:\WINDOWS\
Microsoft.NET\Framework\v2.0.50727\CONFIG directory (your version may differ). If you were to
open this file, you would find numerous XML elements that control ASP.NET settings, various secu-
rity details, debugging support, and so forth.
Although this file can be directly edited using Notepad, be warned that if you alter this file
incorrectly, you may cripple the ability of the runtime to function correctly. This scenario can be far
more painful than a malformed application *.config file, given that XML errors in an application
configuration file affect only a single application, but erroneous XML in the machine.config file can
break a specific version of the .NET platform.
The Assembly Binding “Big Picture”
Now that you have drilled down into the details regarding how the CLR resolves the location of
requested external assemblies, remember that the simple case is, indeed, simple. Many (if not most)
of your .NET applications will consist of nothing more than a group of private assemblies deployed
to a single directory. In this case, simply copy the folder to a location of your choosing and run the

client executable.
5785ch13.qxd 3/31/06 10:56 AM Page 405
CHAPTER 13 ■ INTRODUCING .NET ASSEMBLIES406
As you have seen, however, the CLR will check for client configuration files and publisher policy
assemblies during the resolution process. To summarize the path taken by the CLR to resolve an
external assembly reference, ponder Figure 13-26.
Summary
This chapter drilled down into the details of how the CLR resolves the location of externally referenced
assemblies. You began by examining the content within an assembly: headers, metadata, manifests,
and CIL. Then you constructed single-file and multifile assemblies and a handful of client applica-
tions (written in a language-agonistic manner).
As you have seen, assemblies may be private or shared. Private assemblies are copied to the
client’s subdirectory, whereas shared assemblies are deployed to the Global Assembly Cache (GAC),
provided they have been assigned a strong name. Finally, as you have seen, private and shared
assemblies can be configured using a client-side XML configuration file or, alternatively, via a pub-
lisher policy assembly.
Figure 13-26. Behold the CLR’s path of assembly resolution
5785ch13.qxd 3/31/06 10:56 AM Page 406
407
CHAPTER 14
■ ■ ■
Type Reflection, Late Binding, and
Attribute-based Programming
As shown in the previous chapter, assemblies are the basic unit of deployment in the .NET
universe. Using the integrated object browsers of Visual Studio 2005, you are able to examine the
types within a project’s referenced set of assemblies. Furthermore, external tools such as ildasm.exe
allow you to peek into the underlying CIL code, type metadata, and assembly manifest for a given
.NET binary. In addition to this design-time investigation of .NET assemblies, you are also able to
programmatically obtain this same information using the System.Reflection namespace. To this
end, the first task of this chapter is to define the role of reflection and the necessity of .NET metadata.

The remainder of the chapter examines a number of closely related topics, all of which hinge
upon reflection services. For example, you’ll learn how a .NET client may employ dynamic loading
and late binding to activate types it has no compile-time knowledge of. You’ll also learn how to insert
custom metadata into your .NET assemblies through the use of system-supplied and custom attributes.
To put all of these (seemingly esoteric) topics into perspective, the chapter closes by demonstrating
how to build several “snap-in objects” that you can plug into an extendable Windows Forms
application.
The Necessity of Type Metadata
The ability to fully describe types (classes, interfaces, structures, enumerations, and delegates)
using metadata is a key element of the .NET platform. Numerous .NET technologies, such as object
serialization, .NET remoting, and XML web services, require the ability to discover the format of
types at runtime. Furthermore, COM interoperability, compiler support, and an IDE’s IntelliSense
capabilities all rely on a concrete description of type.
Regardless of (or perhaps due to) its importance, metadata is not a new idea supplied by the
.NET Framework. Java, CORBA, and COM all have similar concepts. For example, COM type libraries
(which are little more than compiled IDL code) are used to describe the types contained within a COM
server. Like COM, .NET code libraries also support type metadata. Of course, .NET metadata has no
syntactic similarities to COM IDL. Recall that the ildasm.exe utility allows you to view an assembly’s
type metadata using the Ctrl+M keyboard option (see Chapter 1). Thus, if you were to open any of
the *.dll or *.exe assemblies created over the course of this book (such as CarLibrary.dll) using
ildasm.exe and then press Ctrl+M, you would find the relevant type metadata (see Figure 14-1).
5785ch14.qxd 3/31/06 1:51 PM Page 407
CHAPTER 14 ■ TYPE REFLECTION, LATE BINDING, AND ATTRIBUTE-BASED PROGRAMMING408
Figure 14-1. Viewing an assembly’s metadata
As you can see, ildasm.exe’s display of .NET type metadata is very verbose (the actual binary
format is much more compact). In fact, if I were to list the entire metadata description representing
the CarLibrary.dll assembly, it would span several pages. Given that this act would be a woeful waste
of paper, let’s just glimpse into some key metadata tokens within the CarLibrary.dll assembly.
Viewing (Partial) Metadata for the EngineState Enumeration
Each type defined within the current assembly is documented using a TypeDef #n token (where TypeDef

is short for type definition). If the type being described uses a type defined within a separate .NET
assembly, the referenced type is documented using a TypeDef #n token (where TypeRef is short for
type reference). A TypeRef token is a pointer (if you will) to the referenced type’s full metadata defini-
tion. In a nutshell, .NET metadata is a set of tables that clearly mark all type definitions (TypeDefs)
and referenced entities (TypeRefs), all of which can be viewed using ildasm.exe’s metadata window.
As far as CarLibrary.dll goes, one TypeDef we encounter is the metadata description of the
CarLibrary.EngineState enumeration (your number may differ; TypeDef numbering is based on
the order in which the VB 2005 compiler processes the source code files):
TypeDef #6 (02000007)

TypDefName: CarLibrary.EngineState (02000007)
Flags : [Public] [AutoLayout] [Class] [Sealed] [AnsiClass] (00000101)
Extends : 01000007 [TypeRef] System.Enum

Field #2 (04000007)

Field Name: engineAlive (04000007)
Flags : [Public] [Shared] [Literal] [HasDefault] (00008056)
DefltValue: (I4) 0
CallCnvntn: [FIELD]
Field type: ValueClass CarLibrary.EngineState

Here, the TypDefName token is used to establish the name of the given type. The Extends meta-
data token is used to document the base class of a given .NET type (in this case, the referenced type,
System.Enum). Each field of an enumeration is marked using the Field #n token. For brevity, I have
simply listed the metadata for EngineState.engineAlive.
5785ch14.qxd 3/31/06 1:51 PM Page 408
CHAPTER 14 ■ TYPE REFLECTION, LATE BINDING, AND ATTRIBUTE-BASED PROGRAMMING 409
Viewing (Partial) Metadata for the Car Type
Here is a partial dump of the Car type that illustrates the following:

• How fields are defined in terms of .NET metadata
• How methods are documented via .NET metadata
• How a single type property is mapped to two discrete member functions
TypeDef #3

TypDefName: CarLibrary.Car (02000004)
Flags : [Public] [AutoLayout] [Class] [Abstract] [AnsiClass] (00100081)
Extends : 01000002 [TypeRef] System.Object
Field #1

Field Name: petName (04000008)
Flags : [Family] (00000004)
CallCnvntn: [FIELD]
Field type: String

Method #1

MethodName: .ctor (06000001)
Flags : [Public] [HideBySig] [ReuseSlot] [SpecialName]
[RTSpecialName] [.ctor] (00001886)
RVA : 0x00002050
ImplFlags : [IL] [Managed] (00000000)
CallCnvntn: [DEFAULT]
hasThis
ReturnType: Void
No arguments.

Property #1

Prop.Name : PetName (17000001)

Flags : [none] (00000000)
CallCnvntn: [PROPERTY]
hasThis
ReturnType: String
No arguments.
DefltValue:
Setter : (06000004) set_PetName
Getter : (06000003) get_PetName
0 Others

First, note that the Car class metadata marks the type’s base class and includes various flags
that describe how this type was constructed (e.g., [public], [abstract], and whatnot). Methods
(such as our Car’s constructor, denoted by .ctor) are described in regard to their parameters, return
value, and name. Finally, note how properties are mapped to their internal get/set methods using
the .NET metadata Setter/Getter tokens. As you would expect, the derived Car types (SportsCar
and MiniVan) are described in a similar manner.
5785ch14.qxd 3/31/06 1:51 PM Page 409
CHAPTER 14 ■ TYPE REFLECTION, LATE BINDING, AND ATTRIBUTE-BASED PROGRAMMING410
Examining a TypeRef
Recall that an assembly’s metadata will describe not only the set of internal types (Car, EngineState, etc.),
but also any external types the internal types reference. For example, given that CarLibrary.dll has
defined two enumerations, you find a TypeRef block for the System.Enum type, which is defined in
mscorlib.dll:
TypeRef #1 (01000001)

Token: 0x01000001
ResolutionScope: 0x23000001
TypeRefName: System.Enum
MemberRef #1


Member: (0a00000f) ToString:
CallCnvntn: [DEFAULT]
hasThis
ReturnType: String
No arguments.
Documenting the Defining Assembly
The ildasm.exe metadata window also allows you to view the .NET metadata that describes the
assembly itself using the Assembly token. As you can see from the following (partial) listing, infor-
mation documented within the Assembly table is (surprise, surprise!) the same information that can
be viewable via the MANIFEST icon. Here is a partial dump of the manifest of CarLibrary.dll (ver-
sion 2.0.0.0):
Assembly

Token: 0x20000001
Name : CarLibrary
Public Key : 00 24 00 00 04 80 00 00 // Etc
Hash Algorithm : 0x00008004
Major Version: 0x00000002
Minor Version: 0x00000000
Build Number: 0x00000000
Revision Number: 0x00000000
Locale: <null>
Flags : [SideBySideCompatible] (00000000)
Documenting Referenced Assemblies
In addition to the Assembly token and the set of TypeDef and TypeRef blocks, .NET metadata also makes
use of AssemblyRef #n tokens to document each external assembly. Given that the CarLibrary.dll
makes use of the MessageBox type, you find an AssemblyRef for System.Windows.Forms, for example:
AssemblyRef #2

Token: 0x23000002

Public Key or Token: b7 7a 5c 56 19 34 e0 89
Name: System.Windows.Forms
Version: 2.0.3600.0
Major Version: 0x00000002
Minor Version: 0x00000000
Build Number: 0x00000e10
5785ch14.qxd 3/31/06 1:51 PM Page 410
CHAPTER 14 ■ TYPE REFLECTION, LATE BINDING, AND ATTRIBUTE-BASED PROGRAMMING 411
Revision Number: 0x00000000
Locale: <null>
HashValue Blob:
Flags: [none] (00000000)
Documenting String Literals
The final point of interest regarding .NET metadata is the fact that each and every string literal in
your code base is documented under the User Strings token, for example:
User Strings

70000001 : (11) L"Car 2.0.0.0"
70000019 : (11) L"Jamming {0} "
70000031 : (13) L"Quiet time "
7000004d : (14) L"Ramming speed!"
7000006b : (19) L"Faster is better "
70000093 : (16) L"Time to call AAA"
700000b5 : (16) L"Your car is dead"
700000d7 : ( 9) L"Be quiet "
700000eb : ( 2) L"!!"
Now, don’t be too concerned with the exact syntax of each and every piece of .NET metadata.
The bigger point to absorb is that .NET metadata is very descriptive and lists each internally defined
(and externally referenced) type found within a given code base.
The next question on your mind may be (in the best-case scenario) “How can I leverage this

information in my applications?” or (in the worst-case scenario) “Why should I care about metadata
in the first place?” To address both points of view, allow me to introduce .NET reflection services. Be
aware that the usefulness of the topics presented over the pages that follow may be a bit of a head-
scratcher until this chapter’s endgame. So hang tight.
■Note You will also find a number of .custom tokens displayed by the MetaInfo window, which documents the
attributes applied within the code base. You’ll learn about the role of .NET attributes later in this chapter.
Understanding Reflection
In the .NET universe, reflection is the process of runtime type discovery. Using reflection services,
you are able to programmatically obtain the same metadata information displayed by ildasm.exe
using a friendly object model. For example, through reflection, you can obtain a list of all types con-
tained within a given assembly (or *.netmodule, as discussed in Chapter 13), including the methods,
fields, properties, and events defined by a given type. You can also dynamically discover the set of
interfaces supported by a given class (or structure), the parameters of a method, and other related
details (base classes, namespace information, manifest data, and so forth).
Like any namespace, System.Reflection contains a number of related types. Table 14-1 lists
some of the core items you should be familiar with.
5785ch14.qxd 3/31/06 1:51 PM Page 411
CHAPTER 14 ■ TYPE REFLECTION, LATE BINDING, AND ATTRIBUTE-BASED PROGRAMMING412
Table 14-1. A Sampling of Members of the System.Reflection Namespace
Type Meaning in Life
Assembly This class (in addition to numerous related types) contains a number of
methods that allow you to load, investigate, and manipulate an assembly
programmatically.
AssemblyName This class allows you to discover numerous details behind an assembly’s
identity (version information, culture information, and so forth).
EventInfo This class holds information for a given event.
FieldInfo This class holds information for a given field.
MemberInfo This is the abstract base class that defines common behaviors for the
EventInfo, FieldInfo, MethodInfo, and PropertyInfo types.
MethodInfo This class contains information for a given method.

Module This class allows you to access a given module within a multifile assembly.
ParameterInfo This class holds information for a given parameter.
PropertyInfo This class holds information for a given property.
To understand how to leverage the System.Reflection namespace to programmatically read
.NET metadata, you need to first come to terms with the System.Type class.
The System.Type Class
The System.Type class defines a number of members that can be used to examine a type’s meta-
data, a great number of which return types from the System.Reflection namespace. For example,
Type.GetMethods() returns an array of MethodInfo types, Type.GetFields() returns an array of
FieldInfo types, and so on. The complete set of members exposed by System.Type is quite expan-
sive; however, Table 14-2 offers a partial snapshot of the members supported by System.Type (see
the .NET Framework 2.0 SDK documentation for full details).
Table 14-2. Select Members of System.Type
Type Member Meaning in Life
IsAbstract These properties (among others) allow you to discover a number of
IsArray basic traits about the Type you are referring to (e.g., if it is an abstract
IsClass method, an array, a nested class, and so forth).
IsCOMObject
IsEnum
IsGenericTypeDefinition
IsGenericParameter
IsInterfaceIsPrimitive
IsNestedPrivate
IsNestedPublic
IsSealed
IsValueType
GetConstructors() These methods (among others) allow you to obtain an array representing
GetEvents() the items (interface, method, property, etc.) you are interested in. Each
GetFields() method returns a related array (e.g., GetFields() returns a FieldInfo
GetInterfaces() array, GetMethods() returns a MethodInfo array, etc.). Be aware that each

GetMembers() of these methods has a singular form (e.g., GetMethod(), GetProperty(),
GetMethods() etc.) that allows you to retrieve a specific item by name, rather than an
GetNestedTypes() array of all related items.
GetProperties()
5785ch14.qxd 3/31/06 1:51 PM Page 412

×