October 31, 2014
Hot Topics:
RSS RSS feed Download our iPhone app

Managed Extensions: Sorting Your Collection Classes

  • August 27, 2004
  • By Tom Archer
  • Send Email »
  • More Articles »

Welcome to this week's installment of .NET Tips & Techniques! Each week, award-winning Architect and Lead Programmer Tom Archer demonstrates how to perform a practical .NET programming task using either C# or Managed C++ Extensions.

In the previous article, I illustrated how to make your classes enumerable via the .NET IEnumerable and IEnumerator interfaces. In this installment of the .NET Tips and Techniques series, I'll take that lesson a step further and illustrate some step-by-step instructions on making your enumerable collections sortable as well.

Implementing the IComparable and IComparer Interfaces

If you do not already have an enumerable collection to test these steps with, you can use the Article.h file found in the previous article. This is the file also used as the beginning point in this week's sample.
  1. Derive the main class (not the collection class) from the IComparable interface:
    __gc class Article : public IComparable
    {
    };
    
  2. Implement the IComparable::CompareTo method, which allows client code to pass an object to be compared against the current instance. Note that the Article sample class has three members that can be used for sorting: Title, Author and Category and here I'm defaulting the sort to the Title member by calling the Title object's built-in CompareTo method. I can do this because the Title member is a String object and the String class implements the IComparable interface:
    __gc class Article : public IComparable
    {
    ...
    public:
      int CompareTo(Object* obj)
      {
        Article* tmp = dynamic_cast<Article*>(obj);
        return(title->CompareTo(tmp->title));
      }
    
  3. Next, you need to define a class for each sort you wish to make available for your class's clients. In this case, I've added classes that allow for sorting by Article::Author and Article::Category. As you can see, each class (ArticleAuthorComparer and ArticleCategoryComparer) derive from the IComparer interface and implements it's sole Compare method, which takes two objects to compare. Within those comparisons, I can perform whatever type of application-specific logic I need to carry about the sorting. For example, for purposes of this demo, I sorted the Author field in ascending order and the Category field in descending order.

    Even if your sorting needs are much more complex, you have complete control over specifying how the items should be sorted by returning a value of less than 0 if the first item is less than the second item, 0 if the items are equal and a value greater than 0 if the first item is greater than the second:

    __gc class Article : public IComparable
    {
    ...
      __gc class ArticleAuthorComparer : public IComparer
      {
      public:
        int Compare(Object* o1, Object* o2)
        {
          Article* p1 = dynamic_cast<Article*>(o1);
          String* p1Author = p1->Author;
    
          Article* p2 = dynamic_cast<Article*>(o2);
          String* p2Author = p2->Author;
    
          // ascending order
          return 1 * p1Author->CompareTo(p2Author);
        }
      };
    
      __gc class ArticleCategoryComparer : public IComparer
      {
      public:
        int Compare(Object* o1, Object* o2)
        {
          Article* p1 = dynamic_cast<Article*>(o1);
          String* p1Category = p1->Category;
    
          Article* p2 = dynamic_cast<Article*>(o2);
          String* p2Category = p2->Category;
    
          // descending order
          return -1 * p1Category->CompareTo(p2Category);
        }
      };
    
  4. While not mandatory, I like to define an enum that client code can use to specify the current sort order. I find this much more self-documenting than using a simple data type such as an int as it forces the client code to specify a value that can be checked at runtime for accuracy. Here are the enum values used in the demo application:
    __value enum ArticleSortOption
    {
      ByTitle,
      ByAuthor,
      ByCategory
    };
    
  5. The last step to making your collection class sortable is to define a sort method that the client can call. As you can see, this public method takes the enum value defined in the previous step as its sole argument and sorts the collection based on that value:
    __gc class ArticleCollection : public IEnumerable
    {
    ...
    protected:
      ArticleSortOption sortOption;
    public:
      void Sort(enum ArticleSortOption sortOption)
      {
        this->sortOption = sortOption;
        switch(sortOption)
        {
          case ArticleSortOption::ByTitle:
          articles->Sort();
          break;
    
          case ArticleSortOption::ByAuthor:
          articles->Sort(new Article::ArticleAuthorComparer);
          break;
    
          case ArticleSortOption::ByCategory:
          articles->Sort(new Article::ArticleCategoryComparer);
          break;
        }
      }
    




Page 1 of 2



Comment and Contribute

 


(Maximum characters: 1200). You have characters left.

 

 


Sitemap | Contact Us

Rocket Fuel