Monday, June 22, 2026

C# Example of Generic class Implementing a generic interface e.g. IComparer

Look the following examples. For Doctor class, I have created DoctorNameComparer class for comparing names of Doctors. Similarly, for Engineer class, I have created EngineerNameComparer class for comparing names of Engineers. 

Let us suppose you have 20 different classes and you want to compare name property for each class then it would become combersome process. You will have to create 20 separate NameComparee classes. The question is how to create just one class and get comparison task done. You can solve this problem by creating a generic class implementing the generic interface, IComparer<T>.
class DoctorNameComparer : IComparer<Doctor>
{
    public int Compare(Doctor? x, Doctor? y)
    {
        if (x == null || y == null)
        {
            throw new ArgumentNullException("Name of doctor is missing");
        }
        return string.Compare(x.Name, y.Name, StringComparison.OrdinalIgnoreCase);
    }
}
class Doctor
{
    public Doctor(string name, int age)
    {
        Name = name;
        Age = age;
    }
    public string Name { get; }
    public int Age { get; }
}
class Engineer
{
    public Engineer(string name, int age)
    {
        Name = name;
        Age = age;
    }
    public string Name { get; }
    public int Age { get; }
}
class EngineerNameComparer : IComparer<Engineer>
{
    public int Compare(Engineer? x, Engineer? y)
    {
        if (x == null || y == null)
        {
            throw new ArgumentNullException("Name of Engineer is missing");
        }
        return string.Compare(x.Name, y.Name, StringComparison.OrdinalIgnoreCase);
    }
}
Example of Generic class Implementing a generic interface IComparer

Create one generic comparer and pass a function that selects the property to compare:
  • Create PropertyComparer<T> class which implements IComparer<T>.
  • Func delegate is constructor parameter of PropertyComparer<T> class. The Func delegate will take type T and will return property from type T.
  • Here, Func Delegate will take an object and will return property of that object.
  • Constructor is used to create delegate object in PropertyComparer class.
class PropertyComparer<T> : IComparer<T>
{
    private readonly Func<T, string> _selector;

    public PropertyComparer(Func<T, string> selector)
    {
        _selector = selector; // delegate initialized
    }

    public int Compare(T? x, T? y)
    {
        if (x == null || y == null)
            throw new ArgumentNullException();

        return string.Compare(
            _selector(x), // delegate invoked
            _selector(y), // delegate invoked.
            StringComparison.OrdinalIgnoreCase);
    }
}
In Main method:
Doctor[] doctors =
{
    new Doctor("Raj", 40),
    new Doctor("Amit", 35)
};

Engineer[] engineers =
{
    new Engineer("Vikas", 30),
    new Engineer("Anil", 25)
};

Array.Sort(doctors, new PropertyComparer<Doctor>(d => d.Name));
Array.Sort(engineers, new PropertyComparer<Engineer>(e => e.Name));
Here, Name is common property to all the classes(e.g. Doctor and Engineer). Such common property can be part of an interface. That interface will be implemented by all the classes(e.g. Doctor and Engineer). Then PropertyComparer<T> can be further improved:

Common Interface for all classes
interface IHasName
{
    string Name { get; }
}
class Doctor : IHasName
{
    public Doctor(string name, int age)
    {
        Name = name;
        Age = age;
    }

    public string Name { get; }
    public int Age { get; }
}

class Engineer : IHasName
{
    public Engineer(string name, int age)
    {
        Name = name;
        Age = age;
    }

    public string Name { get; }
    public int Age { get; }
}
Create a common generic comparer with constraint
class NameComparer<T> : IComparer<T>
    where T : IHasName
{
    public int Compare(T? x, T? y)
    {
        if (x == null || y == null)
            throw new ArgumentNullException();

        return string.Compare(
            x.Name,
            y.Name,
            StringComparison.OrdinalIgnoreCase);
    }
}
In Main method
Array.Sort(doctors, new NameComparer<Doctor>());
Array.Sort(engineers, new NameComparer<Engineer>());

No comments:

Post a Comment

Hot Topics