Learning C# and OOP, Properties, Part 2

Richard Baldwin illustrates reflection and introspection and explains why they are so important with respect to properties.  Comparative information is provided for C# and Java.

Published:  October 29, 2002
By Richard G. Baldwin

C# Programming Notes # 106b


Preface

This lesson is part of a miniseries designed to teach you how to write object-oriented programs using C#.  This is also the second part of a two-part lesson on C# properties.  This miniseries will describe and discuss the necessary and significant aspects of object-oriented programming (OOP) using C#.

The first lesson in the miniseries was entitled Learning C# and OOP: Getting Started, Objects and Encapsulation.  The first part of this two-part lesson was entitled Learning C# and OOP, Properties, Part 1.

Comparisons with Java

The miniseries will also make comparisons between C# and Java with respect to both syntax and OOP concepts.  I will emphasize the similarities between these two programming languages, which are likely to dominate the programming world in the foreseeable future.  By studying these lessons and learning about OOP using C#, you will also be learning quite a lot about OOP using Java.

Relatively high level

I will provide the information in a high-level format, devoid of any prerequisite requirement to know C# syntax.  In those cases where an understanding of C# syntax is required, I will provide the necessary syntax information in the form of sidebars and sample programs.

Therefore, if you have a general understanding of computer programming, you should be able to read and understand the lessons in this miniseries, even if you don't have a background in object-oriented programming, or a background in the C# programming language.

Viewing tip

You may find it useful to open another copy of this lesson in a separate browser window.  That will make it easier for you to scroll back and forth among the different listings while you are reading about them.

Supplementary material

I recommend that you also study the other lessons in my extensive collection of online programming tutorials.  You will find a consolidated index of my online tutorials at www.DickBaldwin.com.

Preview

Second of two parts

This is the second part of a two-part lesson that will concentrate on properties in C# and a comparison of C# properties with Java properties.  A sample C# program is provided to illustrate C# properties.  A sample Java program is also provided to illustrate the similarity of properties between C# and Java.

Review of Part 1

In Part 1, you learned:

  • C# properties act like methods to the creator of the class but look like public fields to clients of the class.  As a result, public fields and properties are indistinguishable to readers of the C# code who don't have ready access to documentation on the class.
  • Java properties look like methods to clients of the class, and it is impossible to confuse properties with public fields in Java.
  • Properties are used for essentially the same purpose in both C# and Java.
  • Both C# properties and Java properties provide the data hiding generally required by good object-oriented design.
  • Properties are not a prerequisite for data hiding.  Data hiding can be easily accomplished in C#, Java, or C++ in the absence of properties.
  • The most important aspect of properties in both C# and Java is their involvement in the processes of reflection and introspection at runtime.
  • Properties are so similar between C# and Java that if you understand properties in either language, you should have no difficulty understanding properties in both languages.

Except for reflection and introspection, part 1 also provided sample programs to illustrate the items in the above list.

Reflection and introspection

As stated above, the most important aspect of properties has to do with reflection and introspection.  This is a process whereby one object can discover and manipulate the properties belonging to another unknown object even though the author of the executing program had no knowledge of the unknown object's class when the executing program was originally written.  Reflection and introspection are discussed in detail in this lesson.

Bound properties and constrained properties

Another important characteristic of properties has to do with bound properties and constrained properties.  This is a process by which an object can be automatically notified when the value of a bound or constrained property belonging to another object changes.  A brief discussion of bound and constrained properties will also be provided in this lesson.

Discussion and Sample Code

My description of a property

The following paragraphs review my description of a property from the first part of this lesson.  This description is based on practical considerations.  For the most part, I will describe the things that must be true for a property to exist, and more importantly, for the property to be really useful.

Name, type, and value

First, a property must have a name, a type, and a value, and possibly some other attributes as well, (such as being read only or read/write).

(In the next lesson, I will discuss indexed properties that have more than one value.)

Same name and type, but different value

A property belongs to an object.  Every object instantiated from the same class will have the same set of properties.  The properties belonging to all the objects instantiated from the same class will have the same names and types, but won't necessarily have the same values from one object to the next.

Where is the value stored?

The value of a property is probably most commonly stored in an instance variable belonging to the object, but that is not a requirement.  The value could be stored in a database, or a disk file, or elsewhere, or could be computed on-the-fly when requested.

The state of the object

The value of a property generally contributes to the state of the object to which it belongs, and when the value of the property changes, the state of the object changes accordingly.

(When the state of an object changes due to a change in a bound property value, other interested objects can be automatically notified of that change of state.)

Standardization is required

To be really useful, the access methodology for a property must be predefined and standardized within a given programming language.  However, the access methodology need not be the same from one language to the next.  The C# programming language accesses properties as fields, while the Java language accesses properties as methods.

The most important aspect of properties

It must be possible for executing code to learn everything there is to know about the properties belonging to an object at runtime, and to be able to access those properties for reading and writing at runtime.

(In C#, this is referred to as reflection.  In Java, it is referred to as introspection based on low-level reflection.)

For .NET, this capability must exist across several languages, even if the language used to define the class and its properties is different from the language used to instantiate objects from the class.

A real-world example

In the first part of this two-part lesson, I discussed the concept of developing software using software components, and how properties fit into that important field.  I'll simply refer you to Part 1 of the lesson for a review of that material.

What really matters is ...

What really matters is that the mechanism for accessing properties must be predefined and standardized so that code can discover and manipulate the properties belonging to an unknown object at runtime.

It's time to look at some code

I'm going to show you a C# program that illustrates properties from three different viewpoints:

  • The viewpoint of the developer of the class that defines properties.
  • The viewpoint of the user of the class to simply set and get property values.
  • The viewpoint of the sophisticated user of the class to discover and use properties at runtime.

The first two viewpoints were covered in the first part of this two-part lesson.  The third viewpoint is the primary topic of this part of the lesson.  While you might find it complex, I hope that you will stick with it until you understand the concepts involved.

A comparable Java program

In addition, I'm going to show you a comparable Java program that accomplishes exactly the same thing as the C# program.  I will compare the code between the two programs and discuss the similarities and the differences.  You will see that even at the complex level of the third viewpoint, the concepts, and even the syntax in the C# program is very similar to the Java program.

Explain in fragments

The complete C# program is shown in Listing C9, and the complete Java program is shown in Listing J9.  These two listings are near the end of the lesson.

In order to help you to focus on important sections of code, I will explain the behavior of these programs in fragments.

A target class

The C# program consists of two classes.  The first class, which I discussed in detail in Part 1, is named TargetClass.  This class defines some properties (as well as some other members), which are accessed by code in the Main method of the other class named Props01.

Listing C1 shows the entire definition of the class named TargetClass.  Of particular interest in this part of the lesson is the boldface material, which defines two properties, named height and width.
 
public class TargetClass{
  //A public instance variable
  public string text;
  
  //This would be a property named
  // color in Java, but not in C#
  private int colorData = 0;
  public void setColor(int data){
    //Validating code goes here
    colorData = data;
  }//end setColor
  public int getColor(){
    return colorData;
  }//end getColor
  
  //This is a property named height
  private int heightData;
  public int height{
    get{
      return heightData;
    }//end get
    set{
      //Validating code goes here
      heightData = value;
    }//end set
  }//end height property

  //This is a property named width
  private int widthData;
  public int width{
    get{
      return widthData;
    }//end get
    set{
      //Validating code goes here
      widthData = value;
    }//end set
  }//end width property
  
}//end TargetClass

Listing C1

An object of type TargetClass

An object instantiated from the class named TargetClass contains:

  • One public instance variable of type string named text.
  • One private instance variable named colorData protected by accessor methods named setColor and getColor.
  • Two properties of type int named height and width.

The Main method

Listing C2 shows the beginning of the class named Props01 and the beginning of the Main method in that class.

This code begins by instantiating and saving a reference to a new object of the class named TargetClass discussed above.  The reference is saved in the reference variable named obj.

The reference to this object was used in Part 1 to access the public instance variable, the hidden data, and the properties of this object.  The reference will be used in this part of the lesson, along with reflection, to discover the properties belonging to the object at runtime.
 
public class Props01{
  static TargetClass obj;
  
  public static void Main(){
    obj = new TargetClass();

Listing C2

The user viewpoint

In this part, we will look at C# properties from the viewpoint of the sophisticated user who needs to first discover and then use properties at runtime.

Three steps

Basically, this process will consist of three steps.  First I will get a reference to an object of the type Type, which represents the type of an object instantiated from the class named TargetClass(This is similar to getting an object of the type Class in Java.)

Next I will use the Type object to get an array of objects of type PropertyInfo.  This array will contain one object for each property belonging to the target object of type TargetClass. (From the previous discussion, you already know that the target object contains two properties, one named height and the other named width.  Therefore, the array will have two elements.)

Finally I will iterate on the array object, using each object in the array to determine the name, type, and current value of the corresponding property belonging to the TargetClass object.

C# and the Object class

Listing C3 shows the first step in this process.  (Note that I skipped the code in the Main method that was covered in Part 1.)
 
    //Some code skipped in Main method

    Type theType = obj.GetType();

Listing C3

All classes in C# (and Java as well) derive either directly or indirectly from the class named Object.  The class named Object defines several methods that are inherited into all other classes.  Some of those methods, (such as Equals and ToString), are meant to be overridden in new classes.  They are declared to be virtual

The GetType method is not virtual

Some of the methods, (such as GetType), are meant to be used as is, without overriding them.  Those methods are not declared to be virtual, so they cannot be overridden.  (Note that the GetType method in C# has the same purpose as the getClass method in Java.)

A Type object

When the GetType method is invoked on an existing object, it returns a reference to an object of the type Type.  According to Microsoft,

"The Type object exposes the metadata associated with the class of the current Object."

Metadata vs. runtime type information

In Java jargon, it would be said that the Type object exposes the runtime type information (RTTI) of the object on which the method is invoked (except that in Java the method is named getClass, and the object that is returned by the method is type Class instead of type Type).

(Actually, the .NET documentation for the typeof operator contains the following statement, "To obtain the run-time type of an expression, you can use the .NET Framework method GetType."  It appears that Microsoft is using the terms metadata and run-time type interchangeably.)

Alternate ways to get a Type object

There are several other ways to get a Type object as well, including the typeof operator and the static GetType method of the Type class (the GetType method invoked in Listing C3 is an instance method, defined in the Object class, and inherited into the TargetClass class).

The GetType method

The static GetType method of the Type class returns a Type object representing a type specified by the name of a class as a string.  (The corresponding method in Java is the method named forName, which is a static method of the class named Class.)

The typeof operator

The typeof operator returns a Type object representing a type specified by the name of its operand.  (This is similar, but not identical, to the instanceof operator in Java, which is used to determine the type of an object based on its reference.)

What is a Type object?

Here is what Microsoft has to say about a Type object:

"This class is the primary way to access metadata, and it acts as a gateway to the Reflection API. Use the members of Type to get information about a type declaration, such as the constructors, methods, fields, properties, and events of a class ..."

Step 1: Getting the Type object

The code in Listing C3 invokes the GetType method on the object instantiated earlier from the class named TargetClass.  The GetType method returns a reference to an object of the type Type.  This object represents the class from which the object was instantiated; TargetClass in this case.  The reference to the Type object is saved in the reference variable named theType.

Step 2:  Getting property information

In this step, we will get information about the properties defined in the class named TargetClass, which is represented by the object of the type Type.

The Type class provides several methods that can be invoked on an object of the Type class, to get information about the type represented by the Type object.  A few of those methods are shown in the following list to illustrate some of the information that is available.  (In general, the names of the methods indicate the type of information that they are designed to provide.)

  • GetProperties
  • GetEvents
  • GetFields
  • GetInterfaces
  • GetMembers
  • GetMethods
  • GetConstructors

Invoking the GetProperties method

The code in Listing C4 invokes the GetProperties method on the Type object.
 
    PropertyInfo[] propInfo = 
               theType.GetProperties();

Listing C4

According to Microsoft, the GetProperties method "Returns all the public properties of the current Type."  The information is returned as an array of objects where each object in the array is of type PropertyInfo.

One PropertyInfo object for each property

Each object of type PropertyInfo in the array represents one of the properties belonging to the target object under investigation.  In this case, the target object is the object instantiated from the class named TargetClass

Number of properties equals number of elements

The number of elements in the array indicates the number of properties belonging to the target object.

Using the Length property of the array

Every array object in C# has a property named Length, whose value is "The total number of elements in all the dimensions of the Array."  Since this is a one-dimensional array, the value of Length is the same as the number of properties belonging to the target object.  The code in Listing C5 gets and displays the value of the Length property.
 
    Console.WriteLine(
        "Number of Public Properties: "
                    + propInfo.Length);

Listing C5

The number of properties

The code in Listing C5 produces the following output on the screen, which matches what we already know about the number of properties defined in the class named TargetClass.

Number of Public Properties: 2

Getting information about each property

Each of the PropertyInfo objects contained in the array can be queried to obtain information about the specific property that it represents.  The code in Listing C6 displays some explanatory text on the screen and then calls the method named DisplayPropertyInfo, passing a reference to the array of PropertyInfo objects to the method.
 
    Console.WriteLine(
        "Descriptions of Properties:");

    DisplayPropertyInfo(propInfo);

Listing C6

The method named DisplayPropertyInfo is designed to get and display information from each element in the array.  As a result, this method gets and displays information about each property in the class named TargetClass.

PropertyInfo objects

An object of the PropertyInfo type contains properties and methods that can be accessed to obtain information about the property that the object represents.  For example, the name and the type of the property represented by the object are stored in the object's properties named Name and PropertyType(Here we have the properties of one object represent attributes of a property of another object.)

The DisplayPropertyInfo method

The method named DisplayPropertyInfo receives a reference to the array of PropertyInfo objects as an incoming parameter.  The entire method consists of a single for loop, and is shown in Listing C7.
 
  public static void 
            DisplayPropertyInfo(
              PropertyInfo[] propInfo){

    for(int i=0;i<propInfo.Length;i++){
      PropertyInfo myPropInfo = 
                           propInfo[i];

      Console.WriteLine("Name: " + 
                      myPropInfo.Name);

      Console.WriteLine("Type: " + 
              myPropInfo.PropertyType);

     //------------------------------//

      //Get and display the value
      MethodInfo readMethod = 
             myPropInfo.GetGetMethod();
      Console.WriteLine("Value: " +
          readMethod.Invoke(obj,null));

    }//end for loop
  }//end DisplayPropertyInfo

Listing C7

Step 3:  Iterate on the array

This method uses a for loop to iterate on the array, extracting name, type, and value information from each object stored in the array.

Getting the name and type information is straightforward.  Getting the value information is a little more complicated. (Listing C7 contains a comment separator to visually separate the code that gets the name and type from the code that gets the value.)

Different issues

From a conceptual viewpoint, there is a significant difference between name and type on one hand, and value on the other.  The name and type of a property is the same for every object instantiated from a given class.  However, the current value of the property will vary among different objects instantiated from the same class.  Therefore, value is specific to each object instantiated from the class, while name and type are the same for all objects instantiated from the class.

Getting the name and type

The code to get and display the name and the type of the property represented by the PropertyInfo object is shown above the visual separator in Listing C7.  As mentioned earlier, this code is straightforward.  All that is required is to access the properties named Name and PropertyType belonging to the PropertyInfo object.  The values of these properties are the name and the type of the property represented by the PropertyInfo object.

Getting the property value for a specific object

The code required to get and display the value of a particular property for a specific object is shown below the visual separator in Listing C7.  This code consists of the following steps (as you will see later, despite its complexity, this is essentially the same process used to accomplish the same task in Java):

  • Invoke the GetGetMethod on the PropertyInfo object to get a reference to an object of type MethodInfo that represents the get method for the particular property represented by the PropertyInfo object.
  • Invoke the Invoke method on the MethodInfo object, passing a reference to the target object as a parameter.  This causes the get method to be invoked on the target object, returning the current value of the property for that object.

The MethodInfo class

An object of the MethodInfo class represents a specific method.  It contains numerous properties and methods that allow you to manipulate the method represented by the object.  For example, there is a method named GetParameters that can be invoked to get a list that identifies the number and types of parameters required by the method.

The Invoke method of the MethodInfo class

In this case, we are interested in the Invoke method of the MethodInfo class.  This method makes it possible for us to invoke the get method represented by the MethodInfo object on a specific object of the TargetClass class.

The Invoke method requires two parameters.  The first parameter is a reference to the object on which we want the get method to be invoked.  In this case, this is the object of the class named TargetClass, which has been the target of the investigation from the beginning.

The second parameter is a reference to an array object, where each element in the array contains a reference to an object that is to be passed as a parameter to the method being invoked.  In this case, the get method requires no parameters, so the code in Listing C7 passes null as the second parameter to the Invoke method.

Invoking the get method on the target object

The result of invoking the Invoke method on the reference to the object of type MethodInfo, while passing the target object as a parameter, is to cause the get method to be invoked on the target object.  The int value returned by the get method is picked up and returned by the Invoke method.  This value is passed to the WriteLine method in Listing C7, which causes it to be displayed on the computer screen.

The screen output

The screen output for the first iteration of the for loop in Listing C7 is shown below:

Name: height
Type: System.Int32
Value: 20

This output indicates that the name of the first property found by our discovery process was height.  This agrees with what we already know to be true.

The property type information

The property type reported by this process looks a little strange.  What in the world is the type System.Int32?

According to the documentation, the type System.Int32 represents a 32-bit signed integer.  However, when we defined the class named TargetClass, we defined the type of the height property as type int, not type System.Int32.  Here is what Microsoft has to say about the relationship between type int and type System.Int32, (with my parenthetical expression inserted):

"The corresponding .NET Framework data type (for type int) is System.Int32. The properties and methods of the int data type are the same as the System.Int32 properties and methods."

Here is what Stanley Lippman has to say in C# Primer, A Practical Approach:

"The keywords for the C# predefined types are aliases for types defined within the System namespace.  For example, int is represented under .NET by the System.Int32 type, and float by the System.single type."

Thus, when we specified type int, we were actually using an alias to specify type System.Int32.

The property value

Finally, the current value represented by the height property on the target object is reported to be 20, which we can verify by examining Listing C9.

The second property named width

The screen output for the second and last iteration of the for loop in Listing C7 is shown below:

Name: width
Type: System.Int32
Value: 50

Because we defined the TargetClass, and wrote the program that defined the properties and set the values of the two properties, we know these to be the correct name, type, and current value.  However, prior knowledge of the answers is not a prerequisite for the correct operation of this discovery process.  It would work correctly if someone else had written the class named TargetClass and had provided us with only the compiled version of the class.

An alternative approach for getting the property value

The code in Listing C8 uses the GetValue method of the PropertyInfo class to get and display the current property value.  This single statement is, in effect, a shorthand replacement for the last two statements inside the for loop in Listing C7.
 
/***********
      Console.WriteLine("Value: " + 
        myPropInfo.GetValue(obj,null));
***********/

Listing C8

The importance of properties

So now you know the true importance of properties in C#.  In my opinion, the importance of properties has nothing to do with making properties look like fields instead of methods.  Similarly, it has nothing to do with information hiding, although those are two interesting by-products of properties.  Rather, the importance of properties is that properties support one aspect of the reflection process.

The reflection process makes it possible for one object to discover and manipulate the properties, events, methods, constructors, fields, etc., belonging to another unknown object, at runtime, with no prior knowledge of the class from which the other object was instantiated.  This, in turn, facilitates the development of very sophisticated software that makes heavy use of information about objects gained at runtime.

A comparable Java program

Now I'm going to show you a Java program that accomplishes exactly the same thing as the C# program discussed above.  As with the C# program, the Java program illustrates properties from three significantly different viewpoints:

  • The viewpoint of the developer of the class that defines properties.
  • The viewpoint of the user of the class to simply set and get property values.
  • The viewpoint of the sophisticated user of the class to discover and use properties at runtime.

Also, as was the case with the C# program, the first two viewpoints were covered in Part 1 of this two-part lesson.

The third viewpoint is the primary topic of this part of the lesson.  While you might find it somewhat complex, I hope that you will stick with it until you understand the concepts involved.

The most significant aspect of the third viewpoint will be the remarkable similarity between the C# code and the Java code, even at this complex level.

Explain in fragments

The complete Java program is shown in Listing J9 near the end of the lesson.  As usual, in order to help you to focus on important sections of code, I will explain the behavior of this program in fragments.

A target class

As was the case with the C# program, the Java program consists of two classes.  The first class, which was explained in detail in Part 1, is named TargetClass.  This Java class mimics the behavior of the C# class shown in Listing C1.

This class defines some properties, which are accessed by code in the main method of the other class named Props01.  Listing J1 shows the definition of the class named TargetClass in its entirety.  The boldface code in Listing J1 shows the definition of three properties named color, height, and width.
 
class TargetClass 
               implements Serializable{
  //A public instance variable
  public String text;
  
  //This is a property named color
  private int colorData = 0;
  public void setColor(int data){
    //Validating code goes here
    colorData = data;
  }//end setColor
  public int getColor(){
    return colorData;
  }//end getColor
  
  //This is a property named height
  private int heightData;
  public void setHeight(int data){
   //Validating code goes here
   heightData = data;
  }//end setHeight
  public int getHeight(){
    return heightData;
  }//end getHeight
  
  //This is a property named width
  private int widthData;
  public void setWidth(int data){
   //Validating code goes here
   widthData = data;
  }//end setwidth
  public int getWidth(){
    return widthData;
  }//end getwidth
  
}//end TargetClass

Listing J1

An object of type TargetClass

A Java object instantiated from the class named TargetClass contains:

  • One public instance variable of type string named text.
  • Three properties of type int named color, height, and width.

The main method

Listing J2 shows the beginning of the class named Props01 and the beginning of the main method for that class.  Except for the difference in the signature of the main method, (which I explained in an earlier lesson), the Java code in Listing J2 is identical to the C# code in Listing C2.
 
public class Props01{
  static TargetClass obj;
  
  public static void main(
                        String[] args){
    obj = new TargetClass();

Listing J2

The code in Listing J2 begins by instantiating and saving a reference to a new object of the class named TargetClass discussed above.  The reference is saved in the reference variable named obj.  The reference was used to access the public instance variable and the properties of this object in Part 1.   In this part, the reference will be used in the introspection process to discover the properties belonging to the object at runtime.

The user viewpoint

As was the case with the C# program, we're getting ready to park the family station wagon and take a ride in a sports car.  We will examine Java properties from the viewpoint of the sophisticated user of the class who needs to first discover and then use properties at runtime.

The bottom line at the beginning

I'm going to give you the bottom line up front.  Our objective is to compare the process of discovering and manipulating properties in Java with the process of discovering and manipulating properties in C#.  We will see that even though the names of the classes and methods that we will use to accomplish this purpose are different, the concepts and mechanisms involved are remarkably similar.  Once you understand how to do this in one language, you should understand how to do it in both languages.

Four steps

This process will consist of four steps.  (Recall that only three steps were required in C#.  An extra step is required in Java.)  If you compare the description of these Java steps with the descriptions of the steps required to accomplish the same thing in C#, you will find them to be almost identical.

A Class object

First I will get a reference to an object of the type Class, which represents the type of an object instantiated from the class named TargetClass.

(Recall that the corresponding object was of the type Type in C#.  Frankly, I prefer the name Type to the name Class, because an object of the type Class in Java can also represent primitive types.  Primitive types are not objects instantiated from classes in Java.)

A BeanInfo object

Next I will use the Class object to get a reference to an object of type BeanInfo, which represents the class named TargetClass at a much deeper level than the object of the class named Class (this is the extra step that is required in Java).  The object of type BeanInfo provides considerably more information about TargetClass than does the object of type Class.

(Note that the BeanInfo object can be configured to represent not only the TargetClass object, but also the superclasses of TargetClass.  However, in this program, I constrained it to preclude information about the superclasses for simplicity.)

An array of PropertyDescriptor objects

Then I will use the BeanInfo object to get an array of objects of type PropertyDescriptor(This corresponds to the second step in C#, which produces an array of objects of type PropertyInfo)  This array will contain one object for each property belonging to the target object of type TargetClass. (From the previous discussion, you already know that the target object contains three properties, named color, height, and width.  Therefore, the array will have three elements.)

Iterate on the array

Finally, I will iterate on the array object, using each object in the array to determine the name, type, and current value of the corresponding property belonging to the TargetClass object.

Java and the Object class

Listing J3 shows the first step in this process.  (This Java listing corresponds to the C# listing in Listing C3.  Note that I skipped the code in the main method that was covered in Part 1.)
 
    //Some code skipped in main method

    Class theType = obj.getClass();

Listing J3

Object defines eleven methods

All classes in Java (and C# as well), derive either directly or indirectly from the class named Object.  The class named Object defines eleven methods that are inherited into all other classes. 

Some methods may be overridden

Some of those methods, (such as equals and toString), are intended to be overridden in new classes.  In Java, they are virtual by default, so they may be freely overridden. 

Some methods are final

Some of the methods, (such as getClass), are intended to be used as is, without overriding them.  Those methods are declared final so that they cannot be overridden.

Invoking the getClass method

When the getClass method is invoked on an existing object, it returns a reference to an object of the type Class.  According to Sun,

"Instances of the class Class represent classes and interfaces in a running Java application."

In Java jargon, it would be said that the Class object exposes the runtime type information (RTTI) of the object on which the method is invoked.

Alternate ways to get a Class object

I know of three ways to get a Class object in Java.  One way is to invoke the getClass method on an object, as illustrated in Listing J3.  (This is similar to invoking the GetType instance method in C#.)

The second way is to invoke the static forName method of the Class class, passing the name of the target class as a String parameter. (This is similar to invoking the static GetType method of the Type class in C#.)

The third way involves Class objects that represent primitive types.  I will defer an explanation of that process until a future lesson.

Step 1: Getting the Class object

The code in Listing J3 invokes the GetClass method on the object instantiated earlier from the class named TargetClass.  The GetClass method returns a reference to an object of the type Class.  This object represents the class from which the object was instantiated; TargetClass in this case.  The reference to the Class object is saved in the reference variable named theType.

The Introspector class

The discovery process in Java is described as introspection using low-level reflection.  The class named Introspector plays an important role in this process.  Here is what Sun has to say about the Introspector class:

"The Introspector class provides a standard way for tools to learn about the properties, events, and methods supported by a target Java Bean.

For each of those three kinds of information, the Introspector will separately analyze the bean's class and superclasses looking for either explicit or implicit information and use that information to build a BeanInfo object that comprehensively describes the target bean."

Note that a Java Bean is a standard software component used in the Java version of software component programming.

Step 2: Getting the BeanInfo object

The Introspector class provides several static methods, including three overloaded versions of a method named getBeanInfo.

The code in Listing J4 uses one of the overloaded versions of the getBeanInfo method to get a BeanInfo object capable of providing information about the target object earlier instantiated from the class named TargetClass. (Since there is no requirement for this step in C#, there is n C# code listing corresponding to Listing J4.)
 
      BeanInfo beanInfo = 
        Introspector.getBeanInfo(
                    theType,theType.
                      getSuperclass());

Listing J4

Two parameters required

This version of the getBeanInfo method requires two parameters.  The first parameter is a Class object representing the class from which the target object was instantiated; TargetClass in this case.

The second parameter is also a Class object.  This object represents a superclass of the target object.  The resulting BeanInfo object will contain information about the target class and all of its superclasses up to, but not including the class represented by the second parameter. 

Use the direct superclass

In this case, the second parameter was the direct superclass of the target class.  Therefore, the resulting BeanInfo object contains information about the target class only (information about superclasses was precluded for simplicity).

Step 3:  Getting property information

This step corresponds to the second step in the C# reflection process.  We will get information about the properties defined in the class named TargetClass, which is now represented by the object of type BeanInfo.

Several methods available

The BeanInfo object provides several methods that can be invoked to get information about the type represented by the BeanInfo object.  A few of those methods are shown in the following list to illustrate some of the information that is available.  (In general, the names of the methods indicate the type of information they are designed to provide.)

  • getPropertyDescriptors
  • getMethodDescriptors
  • getEventSetDescriptors

Invoking the getPropertyDescriptors method

The code in Listing J5 invokes the getPropertyDescriptors method on the BeanInfo object.  (This is similar to invoking the GetProperties method on the Type object in the C# program shown in Listing C4.)
 
      PropertyDescriptor[] propInfo = 
            beanInfo.
              getPropertyDescriptors();

Listing J5

PropertyDescriptor objects

According to Sun, the getPropertyDescriptors method returns "An array of PropertyDescriptors describing the editable properties supported by this bean."

An array of PropertyDescriptor objects

The information is returned as an array of objects where each object in the array is of type PropertyDescriptor.  Each object of type PropertyDescriptor represents one of the properties belonging to the target class under investigation. 

The number of properties

In this case, the target class is the class named TargetClass.  The number of elements in the array indicates the number of properties belonging to objects of the target class.

Using the length property of the array

As in C#, every array object in Java has a final public member variable (constant) named length, whose value is the number of elements in the array. 

In this case, the value of length is the same as the number of properties belonging to the target class.  The code in Listing J6 gets and displays the value of length. (This code corresponds to the code in the C# program shown in Listing C5.)
 
      System.out.println(
               "Number of Properties: "
                    + propInfo.length);

Listing J6

The number of properties

The code in Listing J6 produces the following output on the screen, which matches what we already know about the number of properties defined in the Java class named TargetClass(Recall that the Java class had three properties whereas the corresponding C# class had only two properties.)

Number of Public Properties: 3

Getting information about each property

Each of the PropertyDescriptor objects contained in the array can be queried to obtain information about the specific property that it represents.  The code in Listing J7 displays some explanatory text on the screen and then calls the method named DisplayPropertyInfo, passing a reference to the array of PropertyDescriptor objects to the method.  (The Java code in Listing J7 corresponds to the C# code in Listing C6.)
 
      System.out.println(
        "Descriptions of Properties:");

      displayPropertyInfo(propInfo);

Listing J7

The DisplayPropertyInfo method

As was the case with the C# program, the method named DisplayPropertyInfo is designed to get and display information from each element in the array.  As a result, this method gets and displays information about each property in the class named TargetClass.

The PropertyDescriptor objects

Each object of the PropertyDescriptor type contains several methods that can be invoked to obtain information about the property that the object represents.  For example, the name and the type of the property represented by the object can be obtained by invoking the methods named getName and getPropertyType on the PropertyDescriptor object.

(By now, you should suspect that these are properties of the PropertyDescriptor object, based on JavaBeans Design Patterns.)

Step 4: Iterate on the array of PropertyDescriptor objects

The method named DisplayPropertyInfo receives a reference to the array of PropertyDescriptor objects as an incoming parameter.  The entire method, consisting of a single for loop, is shown in Listing J8.

(This corresponds to Listing C7 in the C# program discussed earlier.  If you compare the two listings, you will find that they are very similar in both syntax and concept.)

  public static void 
      displayPropertyInfo(
        PropertyDescriptor[] propInfo){

    for(int i=0;i<propInfo.length;i++){
      PropertyDescriptor myPropInfo = 
                           propInfo[i];

      System.out.println("Name: " + 
                 myPropInfo.getName());

      System.out.println("Type: " +
         myPropInfo.getPropertyType());

     //------------------------------//

      //Get and display the value
      Method readMethod = 
            myPropInfo.getReadMethod();
      try{
        System.out.println("Value: " + 
          readMethod.invoke(obj,null));
      }catch(Exception e){
        e.printStackTrace();}
    }//end for loop
  }//end displayPropertyInfo

Listing J8

This method uses a for loop to iterate on the array, extracting name, type, and value information using each object stored in the array.

Getting the name and type information is straightforward.  As is the case in C#, getting the value information is a little more complicated.

(Listing J8 contains a comment separator to visually separate the code that gets the name and type from the code that gets the value.)

Different issues

As is the case in C#, there is a significant difference between name and type on one hand, and value on the other.  The name and type of a property is the same for every object instantiated from a given class.  However, the current value of the property will vary among different objects instantiated from the same class.  Therefore, value is specific to each object instantiated from the class, while name and type are the same for all objects instantiated from the class.

Getting the name and type

The code to get and display the name and the type of the property represented by the PropertyDescriptor object is shown above the visual separator in Listing J8.  As mentioned earlier, this code is straightforward.  All that is required is to invoke the methods named getName and getPropertyType belonging to the PropertyDescriptor object.  The values returned by these methods are the name and the type of the property represented by the PropertyDescriptor object.

Getting the property value for a specific object

The code required to get and display the value of a particular property for a specific object is shown below the visual separator in Listing J8.  This code consists of the following steps (note that this is essentially the same process used to accomplish the same task in C#, as shown in Listing C7):

  • Invoke getReadMethod on the PropertyDescriptor object to get a reference to an object of type Method that represents the get method for the particular property represented by the PropertyDescriptor object.
  • Invoke the Invoke method on the Method object, passing a reference to the target object as a parameter.  This causes the get method to be invoked on the target object, returning the current value of the property for that object.

The Method class

An object of the Method class provides information about, and access to, a single method on a class or interface. The reflected method may be a class method or an instance method (including an abstract method).

(The Method class in Java is very similar to the MethodInfo class in C#.)

Numerous methods

The Method object contains numerous methods that allow you to manipulate the method that it represents.  For example, there is a method named getParameterTypes that you can use to get a list that identifies the number and types of parameters required by the method.

(Recall that the C# MethodInfo class has a method named GetParameters that serves essentially the same purpose as the getParameterTypes method in Java.)

The invoke method of the Method class

In this case, we are interested in the invoke method of the Method class.  This method makes it possible to execute the get method represented by the Method object on a specific object of the TargetClass class.

Two parameters required

As was the case in C#, the Java invoke method requires two parameters.  The first parameter is a reference to the object on which we want the get method to be invoked.  In this case, this is the object of the class TargetClass, which has been the target of the investigation from the beginning.

The second parameter is a reference to an array object, where each element in the array contains a reference to an object that is to be passed as a parameter to the method being invoked.  In this case, the get method requires no parameters, so the code in Listing J8 passes null as the second parameter to the invoke method.

(If you compare this portion of Listing J8 with the corresponding portion of Listing C7, you will see that the process involved is essentially the same for C# and Java.  Even the name of the invoke method is the same, except that in C#, the method is named Invoke instead of invoke.)

Invoking the get method on the target object

The result of invoking the invoke method on the reference to the object of type Method, while passing the target object as a parameter, is to cause the get method to be invoked on the target object.  The int value returned by the get method is picked up and returned by the invoke method.  This value is passed to the println method in Listing J8, which causes it to be displayed on the computer screen.

The screen output

The screen output for the first iteration of the for loop in Listing J8 is shown below:

Name: color
Type: int
Value: 15

This output indicates that the name of the first property found by the introspection process was color.  The property was of type int, and the current value was 15.  We know from our prior knowledge of the behavior of the program that this is a correct report.

The properties named height and width

The screen output for the remaining two iterations of the for loop in Listing J8 is shown below:

Name: height
Type: int
Value: 20
Name: width
Type: int
Value: 50

Because we defined the TargetClass, and wrote the program that set the values of the three properties, we know these to be the correct name, type, and current value.  However, prior knowledge of the answers is not a prerequisite for the correct operation of this introspection process.  As in C#, the introspection process would work correctly if someone else had written the class named TargetClass and had provided us with only the compiled version of the class.

Bound and constrained properties

Properties in Java have an extra capability that apparently doesn't exist for properties in C#.

(I strongly suspect that this general capability does exist somewhere in C# and I simply haven't discovered it yet.  I also expect that the day after this article is published, I will receive a flurry of email telling me that I am wrong and that the capability described below does exist for properties in C#.  That will be good because that is how I often learn new things.)

In Java, a bound property has the ability to register interested observer objects and to notify those observer objects each time the property value changes.  A constrained property has the ability to do the same thing with the added stipulation that any observer of a constrained property has the right to veto the change.

Toolbar buttons and menus

A good example of the use of bound properties involves the construction of toolbar buttons that correspond to items on a menu. 

The toolbar button and the corresponding menu item should track one another in terms of being enabled and disabled.  A toolbar button can register itself as an observer on the enabled property of a menu item.  Each time the value of the enabled property of the menu item changes, the toolbar button will be automatically notified, and can change its own enabled property accordingly.  See Understanding Action Objects in Java for a further discussion of this capability.

Summary

Concentrate on properties

This two-part lesson has concentrated on properties in C# and a comparison of C# properties with Java properties.  A sample C# program was provided to illustrate C# properties.  A sample Java program was also provided to illustrate the similarity of properties in C# and Java.

Methods and fields

C# properties act like methods to the creator of the class but look like public fields to clients of the class.  As a result, public fields and properties are indistinguishable to readers of the code who don't have ready access to documentation on the class.

Java properties look like methods to clients of the class.  As a result, it is impossible to confuse properties with public fields in Java.  In my opinion, Java properties are more self-documenting than C# properties.  Beyond that, however, properties are used for essentially the same purpose in both languages.

Properties support data hiding

Both C# properties and Java properties provide the data hiding generally required by good object-oriented design.  However, properties are not a prerequisite for data hiding.  Data hiding can be easily accomplished in C#, Java, or C++ in the total absence of properties.

Reflection and introspection

The most important aspect of properties has to do with reflection and introspection.  This is a process whereby one object can discover and manipulate the properties belonging to another unknown object even though the author of the executing program had no knowledge of the unknown object's class when the executing program was originally written.

Bound properties and constrained properties

Another important characteristic of properties has to do with bound properties and constrained properties. This is a process by which an object can be registered to be automatically notified when the value of a bound or constrained property changes.

C# and Java properties are very similar

Properties are so similar in C# and Java that if you understand properties in either language, you should have no difficulty understanding properties in both languages.

What's Next?

In the next lesson, I will teach you about indexed properties.  These are properties containing multiple values, with each value being accessible through a numeric index.

Complete Program Listings

A complete listing of the C# program discussed in this lesson is shown in Listing C9.
 

/*File Props01.cs
Copyright 2002, R.G.Baldwin

This program is intended to explore and
explain the use of properties in C#.

Program tested using:
Microsoft (R) Visual C# .NET Compiler 
version 7.00.9466
for Microsoft (R) .NET Framework 
version 1.0.3705
Under Win2000 Version 5.0 SP 2

Program output is:
text: Quit
color: 15
height: 20
width: 50
Number of Public Properties: 2
Descriptions of Properties:
Name: height
Type: System.Int32
Value: 20
Name: width
Type: System.Int32
Value: 50
**************************************/
using System;
using System.Reflection;

public class TargetClass{
  //A public instance variable
  public string text;
  
  //This would be a property named
  // color in Java, but not in C#
  private int colorData = 0;
  public void setColor(int data){
    //Validating code goes here
    colorData = data;
  }//end setColor
  public int getColor(){
    return colorData;
  }//end getColor
  
  //This is a property named height
  private int heightData;
  public int height{
    get{
      return heightData;
    }//end get
    set{
      //Validating code goes here
      heightData = value;
    }//end set
  }//end height property

  //This is a property named width
  private int widthData;
  public int width{
    get{
      return widthData;
    }//end get
    set{
      //Validating code goes here
      widthData = value;
    }//end set
  }//end width property
  
}//end TargetClass
//===================================//

public class Props01{
  static TargetClass obj;
  
  public static void Main(){
    obj = new TargetClass();
    
    //Access a public instance 
    // variable
    obj.text = "Quit";
    Console.WriteLine(
                  "text: " + obj.text);
    
    //Invoke public accessor methods
    obj.setColor(15);
    Console.WriteLine(
           "color: " + obj.getColor());
    
    //Set and get a property
    obj.height = 20;
    Console.WriteLine(
              "height: " + obj.height);

    //Set and get another property
    obj.width = 50;
    Console.WriteLine(
                "width: " + obj.width);

    //Now do reflection to identify
    // properties of the object
    Type theType = obj.GetType();
    PropertyInfo[] propInfo = 
               theType.GetProperties();
    Console.WriteLine(
        "Number of Public Properties: "
                    + propInfo.Length);
    Console.WriteLine(
        "Descriptions of Properties:");
    // Display all the properties.
    DisplayPropertyInfo(propInfo);

  }//end Main
  
  public static void 
            DisplayPropertyInfo(
              PropertyInfo[] propInfo){
    for(int i=0;i<propInfo.Length;i++){
      PropertyInfo myPropInfo = 
                           propInfo[i];
      Console.WriteLine("Name: " + 
                      myPropInfo.Name);
      Console.WriteLine("Type: " + 
              myPropInfo.PropertyType);

      //Get and display the value
      MethodInfo readMethod = 
             myPropInfo.GetGetMethod();
      Console.WriteLine("Value: " +
          readMethod.Invoke(obj,null));

/*    Alternative approach for value
      Console.WriteLine("Value: " + 
        myPropInfo.GetValue(obj,null));
*/
      
    }//end for loop
  }//end DisplayPropertyInfo
  
}//end class Props01
//===================================//


Listing C9

A complete listing of the Java program discussed in this lesson is shown in Listing J9.
 
/*File Props01.java
Copyright 2002, R.G.Baldwin

This program is intended to explore and
explain the use of properties in Java,
and is designed for comparison with a
similar C# program.

Program tested using:
SDK 1.4.0 under Win2000 V5.0 SP2

Program output is:
text: Quit
color: 15
height: 20
width: 50
Number of Properties: 3
Descriptions of Properties:
Name: color
Type: int
Value: 15

Name: height
Type: int
Value: 20
Name: width
Type: int
Value: 50
**************************************/
import java.beans.*;
import java.lang.reflect.*;
import java.io.*;

//This class is not declared public in
// order to avoid the rqmt for separate
// files
class TargetClass 
               implements Serializable{
  //A public instance variable
  public String text;
  
  //This is a property named color
  private int colorData = 0;
  public void setColor(int data){
    //Validating code goes here
    colorData = data;
  }//end setColor
  public int getColor(){
    return colorData;
  }//end getColor
  
  //This is a property named height
  private int heightData;
  public void setHeight(int data){
   //Validating code goes here
   heightData = data;
  }//end setHeight
  public int getHeight(){
    return heightData;
  }//end getHeight
  
  //This is a property named width
  private int widthData;
  public void setWidth(int data){
   //Validating code goes here
   widthData = data;
  }//end setwidth
  public int getWidth(){
    return widthData;
  }//end getwidth
  
}//end TargetClass
//===================================//

public class Props01{
  static TargetClass obj;
  
  public static void main(
                        String[] args){
    obj = new TargetClass();
    
    //Access a public instance 
    // variable
    obj.text = "Quit";
    System.out.println(
                  "text: " + obj.text);
    
    //Invoke property methods
    obj.setColor(15);
    System.out.println(
           "color: " + obj.getColor());
    
    obj.setHeight(20);
    System.out.println("height: " + 
                      obj.getHeight());

    obj.setWidth(50);
    System.out.println("width: " + 
                       obj.getWidth());

    //Now do reflection and 
    // introspection to identify
    // properties of the object
    Class theType = obj.getClass();

    try{
      BeanInfo beanInfo = 
      Introspector.getBeanInfo(
                    theType,theType.
                      getSuperclass());

    
      PropertyDescriptor[] propInfo = 
            beanInfo.
              getPropertyDescriptors();

      System.out.println(
               "Number of Properties: "
                    + propInfo.length);
      System.out.println(
        "Descriptions of Properties:");
      // Display all the properties.
      displayPropertyInfo(propInfo);
    }catch(IntrospectionException e){
                  e.printStackTrace();}

  }//end Main
  
  public static void 
      displayPropertyInfo(
        PropertyDescriptor[] propInfo){
    for(int i=0;i<propInfo.length;i++){
      PropertyDescriptor myPropInfo = 
                           propInfo[i];
      System.out.println("Name: " + 
                 myPropInfo.getName());

      System.out.println("Type: " +
         myPropInfo.getPropertyType());

      //Get and display the value
      Method readMethod = 
            myPropInfo.getReadMethod();
      try{
        System.out.println("Value: " + 
          readMethod.invoke(obj,null));
      }catch(Exception e){
        e.printStackTrace();}
    }//end for loop
  }//end displayPropertyInfo
  
}//end class Props01

Listing J9

Review Questions

These review questions apply to both parts of this two-part lesson.

1.  True or false?  C# properties look like methods to clients of the class while Java properties look like public fields to clients of the class.

Answer

2.  True or false?  C# properties provide the data hiding generally required by good object-oriented design, while Java properties do not provide such data hiding.

Answer

3.  True or false?  Properties are a prerequisite for the implementation of data hiding.

Answer

4.  Which of the attributes in the following list are necessary for a property?

  • A.  Name
  • B.  Type
  • C.  Color
  • D.  Value

Answer

5.  True or false?  The value of a property must be stored in an instance variable of the object to which the property belongs.

Answer

6.  What is the minimum number of matching pairs of curly braces { } required to define a property in C#?

Answer

7.  What is the minimum number of matching pairs of parentheses () required to define a property in C#?

Answer

8.  How are the name and type of a property established in C#?

Answer

9.  What is the name of the standard C# class in which the non-static GetType method is defined?  Is GetType a virtual method?

Answer

10.  What is the return type of the GetType method in C#?

Answer

11.  The Object class in Java defines a method with a similar purpose to the GetType method in C#.  What is the name of the Java method?

Answer

12.  What is the return type of the C# method named GetProperties, which is defined in the Type class?

Answer

13.  What is indicated by the value of the Length property of the array object returned by the GetProperties method?

Answer

14.  What is indicated by the values of the properties named Name and PropertyType belonging to an object of the type PropertyInfo?

Answer

15.  What is the name of the method belonging to an object of the MethodInfo class that can be used to invoke the method represented by an object of the MethodInfo class?  How many parameters does this method take, and what is the purpose of those parameters?

Answer



Richard Baldwin is a college professor (at Austin Community College in Austin, Texas) and private consultant whose primary focus is a combination of Java, C#, and XML. In addition to the many platform and/or language independent benefits of Java and C# applications, he believes that a combination of Java, C#, and XML will become the primary driving force in the delivery of structured information on the Web.

Richard has participated in numerous consulting projects and he frequently provides onsite training at the high-tech companies located in and around Austin, Texas.  He is the author of Baldwin's Programming Tutorials, which has gained a worldwide following among experienced and aspiring programmers. He has also published articles in JavaPro magazine.

Richard holds an MSEE degree from Southern Methodist University and has many years of experience in the application of computer technology to real-world problems.

baldwin@DickBaldwin.com


Answers

Answer 15

The name of the method belonging to an object of the MethodInfo class that can be used to invoke the method represented by an object of the MethodInfo class is Invoke.

The Invoke method requires two parameters.  The first is a reference to the object on which the method is to be invoked.  The second is an array containing the parameters that are to be passed to the method when it is invoked.

Back to Question 15

Answer 14

The values of the properties named Name and PropertyType belonging to an object of the type PropertyInfo indicate the name and the type of the property represented by the object of type PropertyInfo.

Back to Question 14

Answer 13

The value of the Length property of the array object returned by the GetProperties method is equal to the number of properties belonging to the object being investigated.

Explanation 13

The array object contains one object of type PropertyInfo for each property belonging to the object being investigated.

Back to Question 13

Answer 12

The return type is PropertyInfo[]

Explanation 12

The GetProperties method returns a reference to an array of PropertyInfo objects.  Therefore, the return type is PropertyInfo[].

Back to Question 12

Answer 11

The name of the Java method is getClass.

Back to Question 11

Answer 10

The return type for the GetType method is Type.

Explanation 10

The GetType method returns a reference to an object of the type Type.  Therefore, the return type for the method is Type.

Back to Question 10

Answer 9

The non-static GetType method is defined in the Object class in C#.  It is not a virtual method, because it is not intended to be overridden.  (Note that a static version of the GetType method is defined in the Type class.)

Back to Question 9

Answer 8

The name and type of the property are established by the line that reads as follows in the definition of the property shown below:

public int height{

Explanation 8

Here is the minimum syntax for the definition of a property in C#.  The first line is similar to a variable declaration with the type of the property being established by the type in the declaration and the name of the property being established by the name in the declaration.
 

  public int height{
    get{
      return ...;
    }//end get

    set{
      ... = value;
    }//end set
  }//end height property

Back to Question 8

Answer 7

There are no parentheses required to define a property in C#.

Explanation 7

Here is the minimum syntax for the definition of a property in C#.  Although get and set act like methods, they do not have a formal argument list enclosed in parentheses.
 

  public int height{
    get{
      return ...;
    }//end get

    set{
      ... = value;
    }//end set
  }//end height property

Back to Question 7

Answer 6

Three sets of matching curly braces are required to define a property in C#.

Explanation 6

Here is the minimum syntax for the definition of a property in C#.
 

  public int height{
    get{
      return ...;
    }//end get

    set{
      ... = value;
    }//end set
  }//end height property

Back to Question 6

Answer 5

False

Explanation 5

The value of a property is probably most commonly stored in an instance variable belonging to the object, but that is not a requirement.  The value could be stored in a database, or a disk file, or could be computed on-the-fly when requested.

Back to Question 5

Answer 4

  • A.  Name
  • B.  Type
  • D.  Value

Back to Question 4

Answer 3

False

Explanation 3

Properties are not a prerequisite for data hiding.  Data hiding can easily be implemented in C#, Java, and C++ in the total absence of properties.

Back to Question 3

Answer 2

False

Explanation 2

Both C# properties and Java properties provide the data hiding generally required by good object-oriented design.

Back to Question 2

Answer 1

False

Explanation 1

The statement is backwards.  A correct statement is, Java properties look like methods to clients of the class while C# properties look like public fields to clients of the class.

Back to Question 1



Copyright 2002, Richard G. Baldwin.  Reproduction in whole or in part in any form or medium without express written permission from Richard Baldwin is prohibited.

baldwin@DickBaldwin.com

-end-


1996, 1997, 1998, 1999, 2000, 2001, 2002 Richard G. Baldwin