Chapter 14: Generics and Collections

Quiz Solutions

Solution to Question 14-1. Indexers are unnamed. You use the this keyword to create an indexer:

public string this[int index]

Solution to Question 14-2. Any type can be used, although it’s most common to use integers.

Solution to Question 14-3. The elements of the collection that you want to sort must implement IComparable.

Solution to Question 14-4. Generics allow you to create type-safe collections without specifying the type the collection will hold when you create the collection.

Solution to Question 14-5. The IEnumerable<T> interface allows your collection to support a foreach loop.

Solution to Question 14-6. The purpose of the yield keyword is to return a value to the IEnumerator object, within the GetEnumerator( ) method.

Solution to Question 14-7. The size of an array is fixed when you create it. A List<T> expands dynamically when you add more elements.

Solution to Question 14-8. The Capacity property of a List indicates the number of elements that the List has room for. The Capacity is increased automatically when more elements are added.

Solution to Question 14-9. A Stack is a “last-in, first-out” collection, and a Queue is a “first-in, first-out” collection. In a Queue, elements are removed in the same order they were inserted. In a Stack, elements are removed in the opposite order.

Solution to Question 14-10. The key in a Dictionary takes the place of an indexer, and allows you to retrieve the associated value. The key can be any type, but it’s usually short. The value is usually a much larger or more complex object associated with the key.

Exercise Solutions

Solution to Exercise 14-1. Create an abstract Animal class that has private members weight and name, and abstract methods Speak( ), Move( ), and ToString( ). Derive from Animal a Cat class and a Dog class that override the methods appropriately. Create an Animal array, populate it with Dogs and Cats, and then call each member’s overridden virtual methods.

The purpose of this exercise is to set up the rest of the exercises in this chapter, and to remind you of how to use arrays and indexers polymorphically. The Animal, Dog, and Cat classes are simple enough to create, although you should remember to make the appropriate methods of Animal abstract. You then need to override those abstract methods in Dog and Cat. In Run( ), you need to allocate enough space for the array of animals, to use a loop (a foreach works well), and to call the overridden virtual methods on each element as an Animal. In our case, we also added a method that only Cat objects have (Purr( )). Within the foreach loop, we cast each Animal to Cat, and if the cast succeeds, call the Purr( ) method. Example A-38 shows how we did it.

Example A-38. One solution to Exercise 14-1

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Exercise_14_1
{
    abstract public class Animal
    {
        protected int weight;
        protected string name;
        public Animal(int weight, string name)
        {
            this.weight = weight;
            this.name = name;
        }
        abstract public void Speak(  );
        abstract public void Move(  );
        abstract public override string ToString(  )
    }

    public class Dog : Animal
    {
        public string Breed { get; set; }
        public Dog(int weight, string name, string breed)
            : base(weight, name)
        {
            this.Breed = breed;
        }
        public override void Speak(  )
        {
            Console.WriteLine("Woof");
        }
        public override void Move(  )
        {
            Console.WriteLine("Run, run, run, drool.");
        }
        public override string ToString(  )
        {
            return "My name is " + this.name + ", I weigh " +
             this.weight + ", and I am a " + this.Breed + "
";
        }
    }

    public class Cat : Animal
    {
        public Cat(int weight, string name) : base(weight, name)
        {
        }
        public override void Speak(  )
        {
            Console.WriteLine("Meow");
        }
        public override void Move(  )
        {
            Console.WriteLine("Run, tumble, nap.");
        }
        public override string ToString(  )
        {
            return "My name is " + this.name + ", I weigh " +
                   this.weight + ", and I know how to purr!
";
        }
        public void Purr(  )
        {
            Console.WriteLine("Purrrrrrrrrrrrrrrrrrrrrrrrrr
");
        }
    }

    public class Tester
    {
        public void Run(  )
        {
            Animal[] myAnimals = new Animal[5];
            myAnimals[0] = new Dog(72, "Milo", "Golden");
            myAnimals[1] = new Cat(12, "Shakespeare");
            myAnimals[2] = new Cat(10, "Allegra");
            myAnimals[3] = new Dog(50, "Dingo", "mixed breed");
            myAnimals[4] = new Dog(20, "Brandy", "Beagle");
            foreach (Animal a in myAnimals)
            {
                a.Speak(  );
                a.Move(  );
                Console.WriteLine(a);
                Cat c = a as Cat;  // cast to cat
                if (c != null)     // if it is a cat
                {
                    c.Purr(  );    // only cats purr
                }
            }
        }
        static void Main(  )
        {
            Tester t = new Tester(  );
            t.Run(  );
        }
    }
}

Solution to Exercise 14-2. Replace the array in Exercise 14-1 with a List. Sort the animals by size. You can simplify by just calling ToString( ) before and after the sort. Remember that you’ll need to implement IComparable.

The first thing you need to do here is replace the array in Run( ) with a List, specifically a List<Animal>. You don’t need to worry about the size of the List; you can just call Add( ) to add each element to the List. Output the values of the list (using a foreach) once, then call Sort( ) on the List, and output the values again.

For the Sort( ) to work, you’ll need to make sure Animal implements IComparable. To sort on the animal’s weight, you’ll need a CompareTo( ) method that delegates responsibility for the comparison to the int version of CompareTo( ), using Animal.weight. Example A-39 shows one way.

Example A-39. One solution to Exercise 14-2

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Exercise_14_2
{
    abstract public class Animal : IComparable
    {
        protected int weight;
        protected string name;
        public Animal(int weight, string name)
        {
            this.weight = weight;
            this.name = name;
        }
        abstract public void Speak(  );
        abstract public void Move(  );
        abstract public override string ToString(  );

        public int CompareTo(Object rhs)
        {
            Animal otherAnimal = rhs as Animal;
            if (otherAnimal != null)
            {
                return this.weight.CompareTo(otherAnimal.weight);
            }
            else
            {
                throw new ApplicationException("Expected to compare animals");
            }
        }
    }

    public class Dog : Animal
    {
        public string Breed { get; set; }

        public Dog(int weight, string name, string breed)
              : base(weight, name)
        {
            this.Breed = breed;
        }
        public override void Speak(  )
        {
            Console.WriteLine("Woof");
        }
        public override void Move(  )
        {
            Console.WriteLine("Run, run, run, drool.");
        }
        public override string ToString(  )
        {
            return "My name is " + this.name + ", I weigh " +
                     this.weight + ", and I am a " + this.Breed;
        }
    }

    public class Cat : Animal
    {
        public Cat(int weight, string name) : base(weight, name)
        {
        }

        public override void Speak(  )
        {
            Console.WriteLine("Meow");
        }
        public override void Move(  )
        {
            Console.WriteLine("Run, tumble, nap.");
        }
        public override string ToString(  )
        {
            return "My name is " + this.name + ", I weigh "
                    + this.weight + ", and I know how to purr!";
        }
        public void Purr(  )
        {
            Console.WriteLine("Purrrrrrrrrrrrrrrrrrrrrrrrrr
");
        }
    }

    public class Tester
    {
        public void Run(  )
        {
            List<Animal> myAnimals = new List<Animal>(  );
            myAnimals.Add(new Dog(72, "Milo", "Golden"));
            myAnimals.Add(new Cat(12, "Shakespeare"));
            myAnimals.Add(new Cat(10, "Allegra"));
            myAnimals.Add(new Dog(50, "Dingo", "mixed breed"));
            myAnimals.Add(new Dog(20, "Brandy", "Beagle"));
            foreach (Animal a in myAnimals)
            {
                Console.WriteLine(a);
            }
            Console.WriteLine("
After sorting by size...");
            myAnimals.Sort(  );
            foreach (Animal a in myAnimals)
            {
                Console.WriteLine(a);
            }
        }
        static void Main(  )
        {
            Tester t = new Tester(  );
            t.Run(  );
        }
    }
}

Solution to Exercise 14-3. Replace the list from Exercise 14-2 with both a Stack and a Queue. Remove the sort function. Output the contents of each collection and see the difference in the order in which the animals are returned.

There’s not a whole lot of challenge to this particular exercise. The goal is to give you some experience using both a stack and a queue. The definitions of the classes don’t change in this exercise; the only difference is in Run( ). As you would expect, if you add the Animal objects to the stack and the queue in the same order, when you output the contents the stack is reversed; the queue isn’t. One solution is shown in Example A-40.

Example A-40. One solution to Exercise 14-3

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Exercise_14_3
{
    abstract public class Animal : IComparable
    {
        protected int weight;
        protected string name;
        public Animal(int weight, string name)
        {
            this.weight = weight;
            this.name = name;
        }
        abstract public void Speak(  );
        abstract public void Move(  );
        abstract public override string ToString(  );

        public int CompareTo(Object rhs)
        {
            Animal otherAnimal = rhs as Animal;
            if (otherAnimal != null)
            {
                return this.weight.CompareTo(otherAnimal.weight);
            }
            else
            {
                throw new ApplicationException("Expected to compare animals");
            }
        }
    }

    public class Dog : Animal
    {
        public string Breed { get; set; }

        public Dog(int weight, string name, string breed)

            : base(weight, name)
        {
            this.Breed = breed;
        }
        public override void Speak(  )
        {
            Console.WriteLine("Woof");
        }
        public override void Move(  )
        {
            Console.WriteLine("Run, run, run, drool.");
        }
        public override string ToString(  )
        {
            return "My name is " + this.name + ", I weigh "
                      + this.weight + ", and I am a " + this.Breed;
        }
    }

    public class Cat : Animal
    {
        public Cat(int weight, string name) : base(weight, name)
        {
        }

        public override void Speak(  )
        {
            Console.WriteLine("Meow");
        }
        public override void Move(  )
        {
            Console.WriteLine("Run, tumble, nap.");
        }
        public override string ToString(  )
        {
            return "My name is " + this.name + ", I weigh "
                    + this.weight + ", and I know how to purr!";
        }
        public void Purr(  )
        {
            Console.WriteLine("Purrrrrrrrrrrrrrrrrrrrrrrrrr
");
        }
    }

    public class Tester
    {
        public void Run(  )
        {
            Console.WriteLine("Adding in the order: Milo,
                        Shakespeare, Allegra, Dingo, Brandy");
            Stack<Animal> myStackOfAnimals = new Stack<Animal>(  );
            myStackOfAnimals.Push(new Dog(72, "Milo", "Golden"));
            myStackOfAnimals.Push(new Cat(12, "Shakespeare"));
            myStackOfAnimals.Push(new Cat(10, "Allegra"));
            myStackOfAnimals.Push(new Dog(50, "Dingo", "mixed breed"));
            myStackOfAnimals.Push(new Dog(20, "Brandy", "Beagle"));

            Queue<Animal> myQueueOfAnimals = new Queue<Animal>(  );
            myQueueOfAnimals.Enqueue(new Dog(72, "Milo", "Golden"));
            myQueueOfAnimals.Enqueue(new Cat(12, "Shakespeare"));
            myQueueOfAnimals.Enqueue(new Cat(10, "Allegra"));
            myQueueOfAnimals.Enqueue(new Dog(50, "Dingo", "mixed breed"));
            myQueueOfAnimals.Enqueue(new Dog(20, "Brandy", "Beagle"));
            Console.WriteLine("The stack...");
            foreach (Animal a in myStackOfAnimals)
            {
                Console.WriteLine(a);
            }

            Console.WriteLine("The queue...");
            foreach (Animal a in myQueueOfAnimals)
            {
                Console.WriteLine(a);
            }
        }
        static void Main(  )
        {
            Tester t = new Tester(  );
            t.Run(  );
        }
    }
}

Solution to Exercise 14-4. Rewrite Exercise 14-2 to allow Animals to be sorted either by weight or alphabetically by name.

This exercise is similar to Example 14-6 in the chapter. You’ve already implemented IComparable for Animal, but now you need to add an overloaded CompareTo( ) method that can compare based on either weight or name. For that, you’ll need to create an AnimalComparer class with a ComparisonType enumeration. Then you’ll need to add a case statement to the overloaded CompareTo( ) method to delegate to either the CompareTo( ) for int, or the one for string. Example A-41 shows our solution. Note that we removed many of the extra methods of Animal, Cat, and Dog for this example, because they’re not needed to sort the animals.

Example A-41. One solution to Exercise 14-4

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Exercise_14_4
{
    abstract public class Animal : IComparable<Animal>
    {
        protected int weight;
        protected string name;
        public Animal(int weight, string name)
        {
            this.weight = weight;
            this.name = name;
        }
        // ** new **
        public static AnimalComparer GetComparer(  )
        {
            return new Animal.AnimalComparer(  );
        }
        public int CompareTo(Animal rhs)
        {
            return this.weight.CompareTo(rhs.weight);
        }
        // ** new **
        public int CompareTo(Animal rhs,
              Animal.AnimalComparer.ComparisonType whichComparison)
        {
            switch (whichComparison)
            {
                case AnimalComparer.ComparisonType.Name:
                    return this.name.CompareTo(rhs.name);
                case AnimalComparer.ComparisonType.Size:
                    return this.weight.CompareTo(rhs.weight);
            }
            return -1;  // all paths must return a value
        }

        // nested class   ** new **
        public class AnimalComparer : IComparer<Animal>
        {
            // how do you want to compare?
            public enum ComparisonType
            {
                Size,
                Name
            };
            private Animal.AnimalComparer.ComparisonType whichComparison;
            public Animal.AnimalComparer.ComparisonType WhichComparison
            {
                get { return whichComparison; }
                set { whichComparison = value; }
            }
            // compare two Animals using the previously set
            // whichComparison value
            public int Compare(Animal lhs, Animal rhs)
            {
                return lhs.CompareTo(rhs, whichComparison);
            }
        }     // end nested class
    }        // end class Animal

    public class Dog : Animal
    {

        public Dog(int weight, string name, string breed) :
            base(weight, name)
        { }
        public override string ToString(  )
        {
            return "My name is " + this.name + ", and I weigh " + this.weight;
        }
    }

    public class Cat : Animal
    {
        public Cat(int weight, string name) :
            base(weight, name)
        { }
        public override string ToString(  )
        {
            return "My name is " + this.name + ", and I weigh " + this.weight;
        }
    }

    public class Tester
    {
        public void Run(  )
        {
            List<Animal> myAnimals = new List<Animal>(  );
            myAnimals.Add(new Dog(70, "Milo", "Golden"));
            myAnimals.Add(new Cat(10, "Shakespeare"));
            myAnimals.Add(new Cat(15, "Allegra"));
            myAnimals.Add(new Dog(50, "Dingo", "mixed breed"));
            myAnimals.Add(new Dog(20, "Brandy", "Beagle"));
            Console.WriteLine("Before sorting...");
            foreach (Animal a in myAnimals)
            {
                Console.WriteLine(a);
            }
            Console.WriteLine("
After sorting by default (weight)...");
            myAnimals.Sort(  );
            foreach (Animal a in myAnimals)
            {
                Console.WriteLine(a);
            }
            Console.WriteLine("
After sorting by name...");
            Animal.AnimalComparer animalComparer = Animal.GetComparer(  );
            animalComparer.WhichComparison =
                      Animal.AnimalComparer.ComparisonType.Name;
            myAnimals.Sort(animalComparer);
            foreach (Animal a in myAnimals)
            {
                Console.WriteLine(a);
            }
            Console.WriteLine("
After sorting explicitly by size...");
            animalComparer.WhichComparison =
                        Animal.AnimalComparer.ComparisonType.Size;
            myAnimals.Sort(animalComparer);
            foreach (Animal a in myAnimals)
            {
                Console.WriteLine(a);
            }
        }
        static void Main(  )
        {
            Tester t = new Tester(  );
            t.Run(  );
        }
    }
}
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset