Previous Page
Next Page

Extending an Inheritance Hierarchy

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:

Understand the inheritance hierarchy 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:

    Graphic
  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.

    Graphic

    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:

    private void Write(string token, Color color)
    {
        target.AppendText(token);
        target.Select(this.index, this.index + token.Length);
        this.index += token.Length;
        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.

  6. 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:

    void ITokenVisitor.VisitComment(string token)
    {
        Write(token, Color.Black);
    }
    
    void ITokenVisitor.VisitIdentifier(string token)
    {
        Write(token, Color.Black);
    }
    
    void ITokenVisitor.VisitKeyword(string token)
    {
        Write(token, Color.Blue);
    }
    
    void ITokenVisitor.VisitOperator(string token)
    {
        Write(token, Color.Black);
    }
    
    void ITokenVisitor.VisitPunctuator(string token)
    {
        Write(token, Color.Black);
    }
    
    void ITokenVisitor.VisitStringLiteral(string token)
    {
        Write(token, Color.Green);
    }
    
    void ITokenVisitor.VisitWhitespace(string token)
    {
        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.
  7. On the Build menu, click Build Solution. Correct any errors, and then rebuild if necessary.

  8. On the Debug menu, click Start Without Debugging.

    The Color Syntax form appears.

  9. On the form, click Open.

    The dummy code is displayed in the rich text box, with keywords in blue and string literals in green.

    Graphic
  10. Close the form to return to Visual Studio 2005.


Previous Page
Next Page