Search code examples
c#genericsicomparer

IComparer C# + generics


How I can write make method Compare in RoomComparerByVolume ? "Define a generic class RoomComparerByVolume<> implementing IComparer interface. Impose a constraint on the type argument so that it should implement the IShape interface. This comparer should perform comparison of rooms by room volume."

    public interface IShape 
    {
        public double Area()
        {
            return 0;
        }
    }
    public class Rectangle : IShape
    {
        public double Length { get; set; }
        public double Width { get; set; }
    
        public double Area()
        {
            return Length * Width;
        }
    }
    
    public class Trapezoid : IShape
    {
        public double Length1 { get; set; }
        public double Length2 { get; set; }
        public double Width { get; set; }
        public double Area()
        { 
        return (Length1 + Length2) * Width / 2;
        }
    }
    
    public class Room<T> where T : IShape, ICloneable, IComparable
    {
        public double Height { get; set; }
        public T Floor;
    
        public double Volume()
        {
            return Height * Height;
        }
    
        public object Clone()
        {
            return new Room<T> { Height = this.Height, Floor = this.Floor };
        }
    
        public int CompareTo(object o)
        {
            Room<T> r = o as Room<T>;
            if (r != null)
                return this.Volume().CompareTo(r.Volume());
            else
                throw new Exception("Unable to compare");
        }
    }
    
    public class RoomComparerByVolume<T> : IComparer<T> where T : IShape
    {
        
    }

Solution

  • Your question is a bit unclear. If compare "by room volume" means in fact compare Area() values and you want to imeplement a corresponding comparer, you can put something like this

    public sealed class ShapeComparerByArea<T> : IComparer<T> where T : IShape
    {
        public int Compare(T left, T right) 
        {
            if (ReferenceEquals(left, right))         
                return 0;
            if (left == null)
                return 1;
            if (right == null)
                return -1;
    
            return left.Area().CompareTo(right.Area());     
        }        
    }
    

    If you want to define comparable Room class (which has Shape Floor) you can put it as

      public class Room : IComparable<Room> {
        public Room(IShape floor, double height) {
          Floor = floor ?? throw new ArgumentNullException(nameof(floor));
          
          Height = height > 0 
            ? height 
            : throw new ArgumentOutOfRangeException(nameof(height));
        }
    
        public IShape Floor { get; }
    
        public double Height { get; }
    
        public double Volume => Floor.Area() * Height;
    
        public int CompareTo(Room other) {
          if (ReferenceEquals(this, other))
            return 0;
          if (other is null)
            return 1;
    
          return Volume.CompareTo(other.Volume);
        }
      }
    

    Finally, RoomComparerByVolume can be

      public sealed class RoomComparerByVolume : IComparer<Room> {
        public int Compare(Room left, Room right) {
          if (ReferenceEquals(left, right))
            return 0;
          if (left == null)
            return 1;
          if (right == null)
            return -1;
    
          return left.Volume.CompareTo(right.Volume);
        }
      }
    

    Demo:

    Room myRoom = new Room(
      new Trapezoid() { Length1 = 5, Length2 = 7, Width = 3}, 
      2.8);
    
    Room myOtherRoom = new Room(
      new Rectangle() { Length = 3, Width = 4 }, 
      2.5);
    
    Console.WriteLine(myRoom.CompareTo(myOtherRoom));
    
    RoomComparerByVolume comparer = new RoomComparerByVolume();
    
    Console.WriteLine(comparer.Compare(myRoom, myOtherRoom));