EqualityComparer for Term

I had an interesting problem to solve today. Given a set of Terms entered in the TaxonomyWebTaggingControl, I had to determine which already existed in a collection. The IEnumerable.Contains() method can do this, but by default this will compare the object references. That is not quite what we want.

The interesting part is that the Contains method has an override that accepts an System.Collections.IEqualityComparer. This gives us the ability to define what "equal" means. For a Term in the Metadata server TermStore, this would typically be the ID. But, what if you are copying values between services (say, from production to QA)? Then perhaps equality is simply the name of the term.

To help with these scenarios, I wrote an equality Comparer that can determine if two terms are equal.

using System;

public class TermEqualityComparer : IEqualityComparer<Term>  
{
  public TermEqualityComparer() { }

  private CompareProperty _propToCompare = CompareProperty.Id;
  public TermEqualityComparer(CompareProperty propertyToCompare)
  {
    _propToCompare = propertyToCompare;
  }

  // Terms are equal if their names and ids are equal.
  public bool Equals(Term x, Term y)
  {
    //Check whether the compared objects reference the same data.
    if (Object.ReferenceEquals(x, y)) return true;

    //Check whether any of the compared objects is null.
    if (Object.ReferenceEquals(x, null) ||
        Object.ReferenceEquals(y, null))
      return false;

    //Check whether the terms' properties are equal.
    bool results = false;
    switch (_propToCompare)
    {
      case CompareProperty.Name:
        results = x.Name == y.Name;
        break;

      case CompareProperty.Id:
        results = x.Id == y.Id;
        break;

      case CompareProperty.NameAndId:
        results = x.Id == y.Id && x.Name == y.Name;
        break;
    }
    return results;
  }

  // If Equals() returns true for a pair of objects
  // then GetHashCode() must return the same
  // value for these objects.
  public int GetHashCode(Term term)
  {
    //Check whether the object is null
    if (Object.ReferenceEquals(term, null))
    {
      return 0;
    }
    else
    {
      int results = default(int);
      switch (_propToCompare)
      {
        case CompareProperty.Name:
          results = term.Name.GetHashCode();
          break;
        case CompareProperty.Id:
          results = term.Id.ToString().GetHashCode();
          break;
        case CompareProperty.NameAndId:
          break;
      }
      return term.Name.GetHashCode();
    }
  }

  public enum CompareProperty
  {
    Name,
    Id,
    NameAndId
  }
}

By default, the class will compare only on ID. To change this behavior, use the overloaded constructor passing the appropriate enumeration value:

TermEqualityComparer teq =  
  new TermEqualityComparer(CompareProperty.Name);
if (termCollection.Contains(term, teq))  
{
  // collection contains term...
}
comments powered by Disqus