More Complex Example: Enumerating Types


Now that we’ve seen how to open and examine assemblies themselves, let’s look at the types that they contain. The word type is somewhat overloaded in .NET. It is often used as a synonym for class, as in “this object is a value type, but that one is a reference type.” I don’t like this usage. If you mean class, say class; don’t go inventing a new word that looks like it means the same thing.[1] The other meaning for the word type is an object of the class System.Type. This class of object contains information that describes another class, such as the base class from which it derives and the members which it contains. If you think of System.Type as “class descriptor,” you’ll have the right mental model.

System.Type is an object that describes a class.

The sample program demonstrates the use of the type object. In this section, I discuss how to view the types that an assembly contains. When the user opens an assembly, clicks a type in the tree control, and then clicks Explore Selected Member, I pop up a dialog box displaying information about the selected type, as shown in Figure 11-5. The next section of this chapter discusses how to use those types to create objects and call methods on them.

The sample program continues here with enumerating types from an assembly.

click to expand
Figure 11-5: Dialog box showing properties of a single type object

You can obtain a type object in several different ways. The GetType method is a member of the universal base class System.Object (discussed in Chapter 2), so you can call this method on any instance of any object you ever have. This method isn’t overridable, so a programmer can’t replace the system’s implementation of this method to fool a caller into thinking that the object is of a different type than it actually is. The GetType operators in Visual Basic and the typeof operator in C# operate on a class name to return a type object describing that class. (Just to confuse things, Visual Basic also contains the TypeOf operator that operates on an individual object.) When we looked at COM interoperation in Chapter 2, we saw that we could use a COM CLSID or a ProgID to get a type object describing a run-time callable wrapper that in turn wrapped a COM object. In the sample program, I load the assembly and call its GetTypes method, which returns an array of all the types contained within that assembly. I put each one on the tree control for you to look at, as shown in Listing 11-2.

There are several different ways to obtain a type object.

Listing 11-2: Code that obtains the list of types and puts each in the tree control

start example
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As _ System.EventArgs) Handles Button1.Click ’ Get assembly name from user Dim dlg As New OpenFileDialog If dlg.ShowDialog() = DialogResult.OK Then ’ Load assembly from selected file CurrentAsm = System.Reflection.Assembly.LoadFrom(dlg.FileName) ’ Place assembly name at root of tree Dim BaseNode As TreeNode BaseNode = TreeView1.Nodes.Add("Assy:" + _ CurrentAsm.GetName.ToString) BaseNode.Tag = CurrentAsm ’ Enumerate each type contained in the assembly Dim ThisType As System.Type For Each ThisType In CurrentAsm.GetTypes() Dim MyNode As TreeNode MyNode = BaseNode.Nodes.Add(ThisType.ToString + " : " + _ ThisType.BaseType.ToString) MyNode.Tag = ThisType ’ Enumerate all the members of this type ’ Add each member to the tree Dim Member As System.Reflection.MemberInfo For Each Member In ThisType.GetMembers(Reflection.BindingFlags.NonPublic Or Reflection.Binding Flags.Public Or Reflection.Bi ndingFlags.Instance Or Reflection.BindingFlags .Static) Dim typenode As TreeNode typenode = MyNode.Nodes.Add(Member.MemberType.ToString _ + ": " + Member.Name) typenode.Tag = Member Next Next End If End Sub
end example

Each type object contains a number of interesting properties about the class that it describes. For example, the BaseType property returns a type object that describes the base class from which the described class derives. The Attributes property returns an enumeration specifying many important characteristics of the described class; for example, whether it is public or private, and whether it is abstract (must inherit from it) or sealed (can’t inherit from it). The type object also contains Boolean properties that provide programmer-friendly access to individual bits of this enumeration, such as IsPublic (a return value of false implying private), IsAbstract, and IsSealed.

The type object contains useful data describing the class itself.

The Attributes property is not the same thing as the CustomAttributes array returned by the GetCustomAttributes method. The former provides a single enumeration of bit flags indicating the properties that the common language runtime must know to properly handle any object, such as whether it’s public or private. This mechanism is sealed by the system for the sake of efficiency in accessing these essential properties. The latter, which you’ve seen throughout the .NET Framework, is an extensible mechanism that allows any programmer to define his own metadata objects (deriving from System.Attribute) for tacking onto assemblies, classes, and their contents. The framework and other parts of .NET make extensive use of this feature as well, for properties that aren’t as vital as the ones in the Attributes enumeration. You tack these onto your objects by means of angle brackets in Visual Basic or square brackets in C#. The sample code in Listing 11-3 shows a class marked with the System.Obsolete attribute as a demonstration (not because there’s anything wrong with the class itself). If you think of these as the programming equivalent of sticky notes, you’ll have the right mental model. Any interested client can detect the presence of this attribute with the Reflection API, as shown here. Visual Studio, for example, shows a warning if you use an object marked in this manner.

The Attributes property is not the same as the CustomAttributes collection.

Listing 11-3: Class marked with a custom attribute

start example
<System.Obsolete()> Public Class Class1 [methods omitted ...] End Class
end example

When programmers examine classes, they usually care most about enumerating their members. The type object supports this capability as well, providing information about the five kinds of members that a class can contain: methods, properties, events, fields (member variables), and constructors. The type object provides methods for accessing the set of all members or any of the five subsets. Each option has both a plural and singular function name for accessing it. The former returns an array containing all of that kind of member. The latter allows you to search for a particular one by means of its name (or parameter list in the case of constructors). The methods are summarized in Table 11-1.

The type object contains functions for examining its members.

Table 11-1: Member Access Functions in System.Type

Kind of Member You Want to See

Returns a Complete Set

Finds a Single Specified Member

Descriptive Object Returned

All

GetMembers

GetMember

MemberInfo

Method

GetMethods

GetMethod

MethodInfo

Property

GetProperties

GetProperty

PropertyInfo

Event

GetEvents

GetEvent

EventInfo

Field

GetFields

GetField

FieldInfo

Constructor

GetConstructors

GetConstructor

ConstructorInfo

The basic MemberInfo object provides a small amount of information about any member, such as its name, the kind of member it is, and the class that contains it. Each kind of member then has its own descriptor object, derived from MemberInfo, that provides additional information about that kind of member, as listed in Table 11-1. For example, the MethodInfo structure has a CallingConvention property and a method named GetParameters that returns an array describing the parameters required by that method. The PropertyInfo structure, on the other hand, contains the CanRead and CanWrite Boolean properties, which specify whether the property is readable, writable, or both. When the user selects a method from the tree control and clicks Explore Selected Member, I pop up a dialog box displaying interesting information from the MethodInfo structure, as shown in Figure 11-6. (Note that I haven’t done this for any other kind of member. I leave this as an exercise for the reader.)

Each kind of member is described by a specific type of object.

click to expand
Figure 11-6: Dialog box displaying information for an individual method

start sidebar
Tips from the Trenches

You’ll notice that in Figure 11-5 the attribute string says both Public and NotPublic. If you look up the values of the TypeAttributes enumeration in the documentation, you’ll see that the AnsiClass, NotPublic, and AutoLayout properties all have the value 0. This value means that these are the default values unless overridden by another bit in the enumeration. If you set a breakpoint in the code, you’ll see that the Attributes property has a value of 1, which means that the value Public is present, overriding the value NotPublic. When I call ToString on this enumeration, it returns NotPublic even though it’s overridden. I find this confusing and wish that ToString was smart enough not to return overridden values.

end sidebar

[1]Some people reply, “You’re wrong, Platt. The word type doesn’t just mean class; it also encom passes other things that aren’t classes, such as interfaces and enumerations.” Wrong. All of these are special cases of classes. An interface is a class with all of its members abstract. An enumeration is a class with all of its members having fixed values. A value type is any class that derives from the System.ValueType base class, a reference type is any class that does not, and so on. Don’t go rede fining the term class and expect people to know what you mean.




Introducing Microsoft. NET
Introducing Microsoft .NET (Pro-Developer)
ISBN: 0735619182
EAN: 2147483647
Year: 2003
Pages: 110

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net