Extending anInheritanceHierarchy
In the following exercise, you will familiarize yourself with a small hierarchy of
interfaces and classes that together implement a very simple framework. The framework
is a Microsoft Windows application that simulates reading a C# source file and
classifying its contents into tokens (identifiers, keywords, operators, and so on). The
framework provides a mechanism for “visiting” each token in turn, performing various
tasks. For example:
• A displaying visitor class that displays the source file in a rich text box.
• A printing visitor class that converts tabs to spaces and aligns braces correctly.
• A spelling visitor class that checks the spelling of each identifier.
• A guideline visitor class that checks that the public identifiers start with a capital
letter and that interfaces start with a capital I.
• A complexity visitor class that monitors the depth of the brace nesting in the code.
• A counting visitor class that counts the number of lines in each method, the
number of members in each class, and the number of lines in each source file.
Understand the inheritancehierarchy and its purpose
1. Start Microsoft Visual Studio 2005.
2. Open the Tokenizer project, located in the \Microsoft Press\Visual CSharp Step by
Step\Chapter 12\Tokenizer folder in your My Documents folder.
3. Display the SourceFile.cs source file in the Code and Text Editor window.
The SourceFile class contains a private array field called tokens:
private IVisitableToken[] tokens =
{
new KeywordToken("using"),
new WhitespaceToken(" "),
new IdentifierToken("System"),
new PunctuatorToken(";"),
};
The tokens array contains a sequence of objects that all implement the
IVisitableToken interface. Together, these tokens simulate the tokens of a simple
“hello, world” source file. (A complete version of this project would parse a
named source file and construct these tokens dynamically.) The SourceFile class
also contains a public method called Accept. The Accept method has a single
parameter of type ITokenVisitor. The body of the Accept method iterates through
the tokens, calling their Accept methods. The Accept method of each token will
process the token in some way, according to the type of the token:
public void Accept(ITokenVisitor visitor)
{
foreach (IVisitableToken token in tokens)
{
token.Accept(visitor);
}
}
In this way, the visitor parameter visits each token in sequence.
4. Display the IVisitableToken.cs source file in the Code and Text Editor window.
The IVisitableToken interface inherits from two other interfaces, the IVisitable
interface and the IToken interface:
interface IVisitableToken : IVisitable, IToken
{
}
5. Display the IVisitable.cs source file in the Code and Text Editor window.
The IVisitable interface declares a single Accept method:
interface IVisitable
{
void Accept(ITokenVisitor visitor);
}
Each object in the array of tokens inside the SourceFile class is accessed using the
IVisitableToken interface. The IVisitableToken interface inherits the Accept
method, and each token implements the Accept method.
6. Click the Class View tab underneath the Solution Explorer window. (If the Class
View tab is not visible, click Class View in the View menu).
This window displays the namespaces, classes, and interfaces defined by the
project.
7. Expand the Tokenizer project, and then expand the {} Tokenizer namespace. The
classes and interfaces in this namespace are listed. Notice the different icons used
to distinguish interfaces from classes. Expand the IVisitableToken interface, and
then expand the Base Types node. The interfaces that the IVisitableToken
interface extends (IToken and IVisitable) are displayed:
8. In the Class View window, right-click the IdentifierToken class and then click Go
To Definition to display it in the Code and Text Editor window (it is actually
located in SourceFile.cs).
The IdentifierToken class inherits from the DefaultTokenImpl abstract class and
the IVisitableToken interface. It implements the Accept method as follows:
void IVisitable.Accept(ITokenVisitor visitor)
{
visitor.VisitIdentifier(this.ToString());
}
The other token classes in this file follow a similar pattern.
9. In the Class View window, right-click the ITokenVisitor interface and then click
Go To Definition. This action displays the ITokenVisitor.cs source file in the Code
and Text Editor window.
The ITokenVisitor interface contains one method for each type of token. The
result of this hierarchy of interfaces, abstract classes, and classes is that you can
create a class that implements the ITokenVisitor interface, create an instance of
this class, and pass this instance as the parameter to the Accept method of a
SourceFile. For example:
class MyVisitor : ITokenVisitor
{
public void VisitIdentifier(string token)
{
}
public void VisitKeyword(string token)
{
}
static void Main()
{
SourceFile source = new SourceFile();
MyVisitor visitor = new MyVisitor();
source.Accept(visitor);
}
}
This will result in each token in the source file calling the matching method in the
visitor object. You could create a number of different visitor classes to perform
numerous different tasks as each token is visited.
In the following exercise, you will create a class that derives from the key framework
interface and whose implementation displays the tokens of the source file in a rich text
box in color syntax (for example, keywords in blue) by using the “visitor” mechanism.
Write the ColorSyntaxVisitor class
1. In the Solution Explorer (click the Solution Explorer tab underneath the Class
View window), double-click Form1.cs to display the Color Syntax form in the
Designer View window.
This form contains an Open button for opening the file to be tokenized, and a rich
text box for displaying the tokens. A rich text box is like an ordinary text box,
except that it can display formatted content rather than simple, unformatted text.
The rich text box in the middle of the form is called codeText, and the button is
called Open.
2. Right-click the form and then click View Code to display the code in the Code and
Text Editor window.
3. Locate the Open_Click method.
This is the method that is called when the Open button is clicked. You must
implement this method so that it displays the tokens defined in the SourceFile
class in the rich text box, by using a ColorSyntaxVisitor object. Change the
Open_Click method so that it looks exactly like this:
private void Open_Click(object sender, EventArgs e)
{
SourceFile source = new SourceFile();
ColorSyntaxVisitor visitor = new ColorSyntaxVisitor(codeText);
source.Accept(visitor);
}
Remember that the Accept method of the SourceFile class iterates through all the
tokens, processing each one by using the specified visitor. In this case, the visitor
is the ColorSyntaxVisitor object, which renders each token in color.
4. Open the ColorSyntaxVisitor.cs source file in the Code and Text Editor window.
The ColorSyntaxVisitor class has been partially implemented. It implements the
ITokenVisitor interface and already contains two fields and a constructor to
initialize a reference to a rich text box, called target, used to display tokens. Your
task is to implement the methods inherited from the ITokenVisitor interface, and
then write the tokens to the rich text box. In the ColorSyntaxVisitor class, the rich
text box is referenced using a variable called target.
5. In the Code and Text Editor window, add a Write method to the
ColorSyntaxVisitor class, exactly as follows:
6. private void Write(string token, Color color)
7. {
8. target.AppendText(token);
9. target.Select(this.index, this.index + token.Length);
10. this.index += token.Length;
11. target.SelectionColor = color;
}
This code appends each token to the rich text box using the specified color. The
Select method of a rich text box selects a block of text indicated by start and end
points; setting the SelectionColor property makes the selected block of text appear
in the specified color. The index variable tracks the current end of the text in the
rich text box, and is updated as new text is appended.
Each of the various “visit” methods will call this Write method to display the
results.
12. In the Code and Text Editor window, add the methods that implement the
ITokenVisitor interface to the ColorSyntaxVisitor class. Use Color.Blue for
keywords, Color.Green for StringLiterals, and Color.Black for all other methods
(Color is a struct defined in the System.Drawing namespace). Notice that this code
implements the interface explicitly; it qualifies each method with the interface
name:
13. void ITokenVisitor.VisitComment(string token)
14. {
15. Write(token, Color.Black);
16. }
17.
18. void ITokenVisitor.VisitIdentifier(string token)
19. {
20. Write(token, Color.Black);
21. }
22.
23. void ITokenVisitor.VisitKeyword(string token)
24. {
25. Write(token, Color.Blue);
26. }
27.
28. void ITokenVisitor.VisitOperator(string token)
29. {
30. Write(token, Color.Black);
31. }
32.
33. void ITokenVisitor.VisitPunctuator(string token)
34. {
35. Write(token, Color.Black);
36. }
37.
38. void ITokenVisitor.VisitStringLiteral(string token)
39. {
40. Write(token, Color.Green);
41. }
42.
43. void ITokenVisitor.VisitWhitespace(string token)
44. {
45. Write(token, Color.Black);
}
TIP
You can either type these methods into the Code and Text Editor window directly,
or you can use a feature of Visual Studio 2005 to add default implementations for
each one and then modify the method bodies with the appropriate code. To do this,
right-click the ITokenVisitor identifier in the class definition: sealed class
ColorSyntaxVisitor : ITokenVisitor In the context menu that appears, point to
Implement Interface and then click the Implement Interface Explicitly option.
Each method will contain a statement that throws an Exception with the message
“This method or operation is not implemented.” Replace this code with that shown
above.
46. On the Build menu, click Build Solution. Correct any errors, and then rebuild if
necessary.
47. On the Debug menu, click Start Without Debugging.
The Color Syntax form appears.
48. On the form, click Open.
The dummy code is displayed in the rich text box, with keywords in blue and
string literals in green.
49. Close the form to return to Visual Studio 2005.
Generating a Class Diagram
The Class View window is useful for displaying the hierarchy of classes and interfaces in
a project. Visual Studio 2005 also enables you to generate class diagrams which depict
this same information graphically (you can also use a class diagram to add new classes
and interfaces, and define methods, properties, and other class members).
To generate a new class diagram, click the Project menu, and then click Add New Item.
In the Add New Item window select the Class Diagram template and then click Add. This
action will generate an empty diagram, and you can create new types by dragging items
from the Class Designer category in the Toolbox. You can generate a diagram of all
existing classes by clicking and dragging them individually from the Class View window,
or by clicking and dragging the namespace to which they belong. The diagram shows the
relationships between the classes and interfaces, and you can expand the definition of
each class to show its contents. You can drag the classes and interfaces around to make
the diagram more readable, as shown in the following image:
.
Extending an Inheritance Hierarchy
In the following exercise, you will familiarize yourself with a small hierarchy of
interfaces and classes.
number of members in each class, and the number of lines in each source file.
Understand the inheritance hierarchy and its purpose
1. Start Microsoft