Using a delegate with a container class to sort the collection and return a sorted array using different sort criteria

image_pdfimage_print

   


/*
C# Programming Tips & Techniques
by Charles Wright, Kris Jamsa

Publisher: Osborne/McGraw-Hill (December 28, 2001)
ISBN: 0072193794
*/
 
// SortEmpl.cs -- Demonstrates using a delegate with a container class to
//                sort the collection and return a sorted array using different
//                sort criteria.
//
//                Compile this program with the following command line:
//                    C:>csc SortEmpl.cs
using System;
using System.ComponentModel;

namespace nsDelegates
{

    public class SortEmpl
    {
        // Declare an enum for the sort methods.
        enum SortBy {Name, ID, ZIP};
        // Create a container to get the clsEmployee object collection
        static public clsEmployeeContainer container = new clsEmployeeContainer ();
        static public void Main ()
        {
            container.Add (new clsEmployee ("John", "Smith", "87678", 1234));
            container.Add (new clsEmployee ("Marty", "Thrush", "80123", 1212));
            container.Add (new clsEmployee ("Milton", "Aberdeen", "87644", 1243));
            container.Add (new clsEmployee ("Marion", "Douglas", "34567", 3454));
            container.Add (new clsEmployee ("Johnathon", "Winters", "53422", 3458));
            container.Add (new clsEmployee ("William", "Marmouth", "12964", 3658));
            container.Add (new clsEmployee ("Miles", "O'Brien", "63445", 6332));
            container.Add (new clsEmployee ("Benjamin", "Sisko", "57553", 9876));

            // Show the unsorted employee list.
            Console.WriteLine ("Unsorted employee list:");
            ComponentCollection collectionList = container.GetEmployees();
            foreach (clsEmployee emp in collectionList)
            {
                Console.WriteLine ("	" + emp);
            }

            // Sort the employees by last name and show the list.
            Console.WriteLine ("
Sorted by last name:");
            clsEmployee [] arr = SortList (SortBy.Name);
            foreach (clsEmployee emp in arr)
            {
                Console.WriteLine ("	" + emp);
            }

            // Sort the employees by ID number and show the list.
            Console.WriteLine ("
Sorted by employee ID:");
            arr = SortList (SortBy.ID);
            foreach (clsEmployee emp in arr)
            {
                Console.WriteLine ("	" + emp);
            }

            // Sort the employees by ZIP code and show the list.
            Console.WriteLine ("
Sorted by ZIP code:");
            arr = SortList (SortBy.ZIP);
            foreach (clsEmployee emp in arr)
            {
                Console.WriteLine ("	" + emp);
            }
        }
        // Define a method that will create the proper delegate according to
        // the sort that is needed.
        static clsEmployee [] SortList (SortBy iSort)
        {
            clsEmployeeContainer.CompareItems sort = null;
            switch (iSort)
            {
                case SortBy.Name:
                    sort = new clsEmployeeContainer.CompareItems(clsEmployee.CompareByName);
                    break;
                case SortBy.ID:
                    sort = new clsEmployeeContainer.CompareItems(clsEmployee.CompareByID);
                    break;
                case SortBy.ZIP:
                    sort = new clsEmployeeContainer.CompareItems(clsEmployee.CompareByZip);
                    break;
            }
            // Do the sort and return the sorted array to the caller.
            return (container.SortItems (sort, false));
        }
    }

    public class clsEmployee : Component
    {
        // Define an employee class to hold one employee's information.
        public clsEmployee (string First, string Last, string Zip, int ID)
        {
            FirstName = First;
            LastName = Last;
            EmployeeID = ID;
            ZipCode = Zip;
        }
        public string  FirstName;
        public string  LastName;
        public string  ZipCode;
        public int      EmployeeID;

        // Define a method to sort by name
        static public int CompareByName (object o1, object o2)
        {
            clsEmployee emp1 = (clsEmployee) o1;
            clsEmployee emp2 = (clsEmployee) o2;
            return (String.Compare (emp1.LastName, emp2.LastName));
        }

        // Define a method to sort by ZIP code
        static public int CompareByZip (object o1, object o2)
        {
            clsEmployee emp1 = (clsEmployee) o1;
            clsEmployee emp2 = (clsEmployee) o2;
            return (String.Compare (emp1.ZipCode, emp2.ZipCode));
        }

        // Define a method to sort by employee ID number.
        static public int CompareByID (object o1, object o2)
        {
            clsEmployee emp1 = (clsEmployee) o1;
            clsEmployee emp2 = (clsEmployee) o2;
            return (emp1.EmployeeID - emp2.EmployeeID);
        }
        // Override ToString() for diagnostic purposes
        public override string ToString ()
        {
            return (FirstName + " " + LastName + ", ZIP " + ZipCode + ", ID "  + EmployeeID);
        }
    }

    // Derive a class to hold the clsEmployee objects
    public class clsEmployeeContainer
    {
        private Container cont = new Container();
        public void Add (clsEmployee empl)
        {
            cont.Add (empl);
        }
        // Declare an array to return to the caller
        clsEmployee [] arrEmployee;

        // Declare a delegate to compare one employee object to another
        public delegate int CompareItems (object obj1, object obj2);

        // Define a sort function that takes a delegate as a parameter. The Reverse
        // parameter can be used to reverse the sort.
        public clsEmployee [] SortItems (CompareItems sort, bool Reverse)
        {
            // Get the clsEmployee objects in the container.
            ComponentCollection employees = cont.Components;
            // Create an array large enough to hold the references
            arrEmployee = new clsEmployee[employees.Count];
            // Copy the collection into the reference. The Container class will not
            // let us sort the collection itself.
            employees.CopyTo (arrEmployee, 0);

            // Do a simple bubble sort. There are more efficient sorting algorithms,
            // but a simple sort is all we need.
            while (true)
            {
                int sorts = 0;
                for (int x = 0; x < arrEmployee.Length - 1; ++x)
                {
                   int result;
                    // Sort in the reverse order if if the Reverse parameter equals true
                   if (Reverse == true)
                       result = sort (arrEmployee&#91;x + 1&#93;, arrEmployee&#91;x&#93;);
                   else
                       result = sort (arrEmployee&#91;x&#93;, arrEmployee&#91;x + 1&#93;);
                    // Reverse the two elements if the result is greater than zero
                   if (result > 0)
                   {
                       clsEmployee temp = arrEmployee[x];
                       arrEmployee[x] = arrEmployee[x+1];
                       arrEmployee[x+1] = temp;
                       ++sorts;
                   }
                }
                // If we did no sorts on this go around, the sort is complete.
                if (sorts == 0)
                    break;
            }
            // Return the sorted array to the caller.
            return (arrEmployee);
        }
        // Return the collection to the caller.
        public ComponentCollection GetEmployees ()
        {
            return (cont.Components);
        }
    }
}