How to use the IComparable interface and the IComparer interface in Visual C++ .NET 2003 or in Visual C++ 2005 (816192)



The information in this article applies to:

  • Microsoft .NET Framework 1.1
  • Microsoft Visual C++ 2005 Express Edition
  • Microsoft Visual C++ .NET (2003)


For a Microsoft Visual Basic .NET version of this article, see 321292.
For a Microsoft Visual C# .NET version of this article, see 320727.

This article refers to the following Microsoft .NET Framework Class Library namespaces:
  • System
  • System::Collections

SUMMARY

The IComparable interface is implemented by types that have values that can be sorted, such as the numeric classes and the string classes.

The IComparer interface permits you to customize the sort order of a collection. You can do this by using the IComparer interface in conjunction with the Array.Sort method and with the Array.BinarySearch method.


IN THIS TASK

INTRODUCTION

The IComparable interface and the IComparer interface are discussed in the same article for two reasons:
  • The IComparable interface and the IComparer interface are frequently used together.
  • Although the IComparable interface and the IComparer interface are similar and have similar names, the purposes that they serve are somewhat different.

If you have an array of types, such as String or Int32 that already support the IComparer interface, you can sort that array without providing any explicit reference to the IComparer interface. In this case, the elements of the array are cast to the default implementation of the IComparer interface (Comparer.Default) for you. However, if you want to provide sorting or comparison capability for your custom objects, you must implement either or both of these interfaces.

Note The concepts that are described in this article can be implemented by using Microsoft Visual C++ .NET 2002 or by using the .NET Framework 1.0. However, when you run the sample code, you may receive runtime exceptions, such as System.TypeLoadException. System.TypeLoadException is a known bug in Visual C++ .NET 2002.

back to the top

Requirements

The following list outlines the recommended hardware, software, network infrastructure, and service packs that you need:
  • Visual C++ .NET 2003 or Visual C++ 2005
  • The .NET Framework 1.1 or later
This article assumes that you are familiar with the following topics:

C++ programming concepts (an intermediate level of understanding)

back to the top

Use the IComparable interface

You can use the IComparable interface to compare two objects of a particular type. You must implement the IComparable interface if you want to provide any sorting capability for your object.

To help you understand the IComparable interface, you can think of the IComparable interface as a way to do a default sort order for your objects. For example, if you have an array of objects of your type, and you call the Sort method on that array, the IComparable interface provides the comparison of objects during the sort. When you implement the IComparable interface, you must implement the CompareTo method as shown in the following code sample:
// Implement IComparable::CompareTo to provide the default sort order.
int IComparable::CompareTo(Object *obj)
{
	car * c = __try_cast<car*>(obj);
	return String::Compare(this->make, c->make);
}
The comparison in the method is different depending on the data type of the value that is being compared. The String::Compare method is used in this example because the property that is selected for the comparison is a string.

Note In the previous code sample, car is the class that you want to provide the ordering capability for.

back to the top

Use the IComparer interface

The IComparer interface provides additional comparison mechanisms. For example, you may want to provide sorting of your class on several fields or on several properties. You may want to provide a sort in ascending order or a sort in descending order, or both, on the same field.

To use the IComparer interface, follow these steps:
  1. Declare a class that implements the IComparer interface, and then implement the Compare method. See the following code sample:
    __gc class car::sortYearAscendingHelper: public IComparer
    {
    private:
    	int IComparer::Compare(Object *a, Object *b)
        {
    		car *c1 = __try_cast<car*>(a);
    		car *c2 = __try_cast<car*>(b);
    
    		if (c1->year > c2->year)
    			return 1;
    
    		if (c1->year < c2->year)
    			return -1;
    
    		else
    			return 0;
        }
    };
    Note The IComparer::Compare method requires a tertiary comparison. After the tertiary comparison, 1, 0, or -1 is returned depending on whether one value is greater than, equal to, or less than the other value. The sort order can be changed to an ascending sort order or to a descending sort order by switching the logical operators in the IComparer::Compare method.

    Note The class in the previous code sample is declared first inside the car class that you want to provide the sorting capability for and then defined outside the car class.
  2. Declare a method that returns an instance of your IComparer object. See the following code sample:
    // This method returns the IComparer object for the sort helper.
    IComparer* car::sortYearAscending()
    {      
        return __try_cast<IComparer*>(new sortYearAscendingHelper());
    }
    Note The method in the previous code sample is first declared as static inside the car class and then defined outside the car class. The object is used as the second argument when you call the overloaded Array::Sort method that accepts the IComparer object. See the following code sample:
    Array::Sort(carlist,car::sortYearAscending());
    In the previous code sample, carlist is an array of car objects.
back to the top

Follow the step-by-step example

The following example shows you how to use the IComparable interface and the IComparer interface. A class that is named car is created. The car object has the make property and the year property. A sort in ascending order for the make property is enabled through the IComparable interface. A sort in descending order on the make property is enabled through the IComparer interface. Both the sort in ascending order and the sort in descending order are provided for the year property by using the IComparer interface.
  1. Start Microsoft Visual Studio .NET 2003 or Microsoft Visual Studio 2005.
  2. On the File menu, point to New, and then click Project.

    The New Project dialog box appears.
  3. Under Project Types, click Visual C++ Projects.

    Note In Visual Studio 2005, click Visual C++ under Project Types.
  4. Under Templates, click Console Application (.NET).

    Note In Visual Studio 2005, click Windows Forms Control Library under Templates.
  5. In the Name box, type CompareInterfaces, and then click OK.
  6. In Solution Explorer, expand all the folders, and then double-click the CompareInterfaces.cpp file in the Source Files folder.
  7. Add the following code to the top of the Code window before the _tmain function:
    using namespace System::Collections;
  8. Add the following code after the using statements and before the _tmain function:
    public __gc class car : public IComparable
    {
    private:
    	int year;
    	String * make;
    
    public:
    	car(void){};
    	~car(void){};
    
    public:
    		
    	car(String *Make,int Year)
        {
            make = Make;
            year = Year;
        }
    	
        __property String* get_Make() 
        {
            return make; 
        }
        __property void set_Make(String* Make)
        {
            make = (Make); 
        }
        __property int get_Year()
        { 
            return year; 
        }
        __property void set_Year(int Year)
        {
            year = Year; 
        }
    
    public:
    
    	// Implement IComparable CompareTo to provide the default sort order.
    	int IComparable::CompareTo(Object *obj)
    	{
    		car * c = __try_cast<car*>(obj);
    		return String::Compare(this->make, c->make);
    	}
    
    	static IComparer* sortYearAscending();
    	static IComparer* sortYearDescending();
    	static IComparer* sortMakeDescending();
    
    private:
    	__gc class sortYearAscendingHelper;
    	__gc class sortYearDescendingHelper;
    	__gc class sortMakeDescendingHelper;
    
    };
    
    // Nested classes start here.
    // This nested class does the ascending sort on the year property.
    __gc class car::sortYearAscendingHelper: public IComparer
    {
    private:
    	int IComparer::Compare(Object *a, Object *b)
        {
    		car *c1 = __try_cast<car*>(a);
    		car *c2 = __try_cast<car*>(b);
    
    		if (c1->year > c2->year)
    			return 1;
    
    		if (c1->year < c2->year)
    			return -1;
    
    		else
    			return 0;
        }
    };
    
    // This nested class does the descending sort on the year property.
    __gc class car::sortYearDescendingHelper : public IComparer
    {
    	int IComparer::Compare(Object *a, Object *b)
        {
    		car *c1= __try_cast<car*>(a);
    		car *c2= __try_cast<car*>(b);
    
    		if (c1->year < c2->year)
    			return 1;
    
    		if (c1->year > c2->year)
    			return -1;
    
    		else
    			return 0;
        }
    };
    		 
     // This nested class does the descending sort on the make property.
    __gc class car::sortMakeDescendingHelper : public IComparer
    {
    	int IComparer::Compare(Object *a, Object *b)
        {
    		car *c1 = __try_cast<car*>(a);
    		car *c2 = __try_cast<car*>(b);
    		return String::Compare(c2->make,c1->make);
        }
    };
    // Nested classes end here.
    
    // This method returns the IComparer object for the sort helper.
    IComparer* car::sortYearAscending()
    {      
        return __try_cast<IComparer*>(new sortYearAscendingHelper());
    }
    
    // This method returns the IComparer object for the sort helper.
    IComparer* car::sortYearDescending()
    {      
        return __try_cast<IComparer*>(new sortYearDescendingHelper());
    }
    
    // This method returns the IComparer object for the sort helper.
    IComparer* car::sortMakeDescending()
    {      
    	return __try_cast<IComparer*>(new sortMakeDescendingHelper());
    }
    Note You must add the common language runtime support compiler option (/clr:oldSyntax) in Visual C++ 2005 to successfully compile the previous code sample. To add the common language runtime support compiler option in Visual C++ 2005, follow these steps:
    1. Click Project, and then click <ProjectName> Properties.

      Note <ProjectName> is a placeholder for the name of the project.
    2. Expand Configuration Properties, and then click General.
    3. Click to select Common Language Runtime Support, Old Syntax (/clr:oldSyntax) in the Common Language Runtime support project setting in the right pane, click Apply, and then click OK.
    For more information about the common language runtime support compiler option, visit the following Microsoft Web site:

    /clr (Common Language Runtime Compilation)
    http://msdn2.microsoft.com/en-us/library/k8d11d4s.aspx

  9. Add the following helper function that displays the car object properties before the _tmain function and after the code that you added in the previous step:
    void DisplayCars(car *carlist[])
    {
    	for(int i=0;i<carlist->Length;i++)
    	{
    		car *c = __try_cast<car*>(carlist->get_Item(i));
    		Console::WriteLine(String::Concat(c->Make,S"\t\t", c->Year.ToString()));
    	}
    }
  10. Replace the code of the _tmain function with the following code:
    car  *carlist[];
    carlist = new car *[6];
    carlist[0]= new car(S"Ford",1992);
    carlist[1]= new car(S"Fiat",1988);
    carlist[2]= new car(S"Buick",1932);
    carlist[3]= new car(S"Ford",1932);
    carlist[4]= new car(S"Dodge",1999);
    carlist[5]= new car(S"Honda",1977);
    
    // Write out a header for the output.
    Console::WriteLine(S"Array - Unsorted\n");
    DisplayCars(carlist);
    
    // Demo IComparable by sorting the array with the "default" sort order.
    Array::Sort(carlist);
    Console::WriteLine(S"\nArray - Sorted by Make (Ascending - IComparable)\n");
    DisplayCars(carlist);
    
    // Demo the ascending sort of the numeric value with IComparer.
    Array::Sort(carlist,car::sortYearAscending());
    Console::WriteLine(S"\nArray - Sorted by Year (Ascending - IComparer)\n");
    DisplayCars(carlist);
    
    // Demo the descending sort of the string value with IComparer.
    Array::Sort(carlist,car::sortMakeDescending());
    Console::WriteLine(S"\nArray - Sorted by Make (Descending - IComparer)\n");
    DisplayCars(carlist);
    
    // Demo the descending sort of the numeric value with IComparer.
    Array::Sort(carlist,car::sortYearDescending());
    Console::WriteLine(S"\nArray - Sorted by Year (Descending - IComparer)\n");
    DisplayCars(carlist);
    
    Console::ReadLine(); 
    return 0;
  11. Press CTRL+SHIFT+S to save the project.
  12. Press CTRL+SHIFT+B to build the solution.
  13. Press CTRL+F5 to run the program.

    The following output appears in the Console window:
    Array - Unsorted
    
    Ford            1992
    Fiat            1988
    Buick           1932
    Ford            1932
    Dodge           1999
    Honda           1977
    
    Array - Sorted by Make (Ascending - IComparable)
    
    Buick           1932
    Dodge           1999
    Fiat            1988
    Ford            1932
    Ford            1992
    Honda           1977
    
    Array - Sorted by Year (Ascending - IComparer)
    
    Ford            1932
    Buick           1932
    Honda           1977
    Fiat            1988
    Ford            1992
    Dodge           1999
    
    Array - Sorted by Make (Descending - IComparer)
    
    Honda           1977
    Ford            1932
    Ford            1992
    Fiat            1988
    Dodge           1999
    Buick           1932
    
    Array - Sorted by Year (Descending - IComparer)
    
    Dodge           1999
    Ford            1992
    Fiat            1988
    Honda           1977
    Buick           1932
    Ford            1932
back to the top

REFERENCES

For additional information about IComparable members in the .NET Framework, visit the following Microsoft Developer Network (MSDN) Web site:
For additional information about IComparer members in the .NET Framework, visit the following MSDN Web site:back to the top

Modification Type:MajorLast Reviewed:1/17/2006
Keywords:kbCOMInterop kbCollections kbProgramming kbinterop kbConsole kbHOWTOmaster KB816192 kbAudDeveloper