shybovycha
shybovycha

Reputation: 12265

IComparer<T> could not use class as a parameter

As I asked in my previous question, I got stuck with IComparer<T> implementation.

I got an interface and class, implementing one:

public interface IRoom
{
    // ...
}

public class Room : IRoom
{
    // ...
}

And a comparer parent-child classes:

public abstract class RoomComparer : IComparer<Room>
{
    public RoomComparer()
    {
    }

    public abstract int Compare(Room x, Room y);
}

public class StandardMultipliedSquareMetersComparer : RoomComparer
{
    public StandardMultipliedSquareMetersComparer()
    {
    }

    public override int Compare(Room a, Room b)
    {
        // ...
    }
}

public class SquareMetersComparer : RoomComparer
{
    public SquareMetersComparer()
    {
    }

    public override int Compare(Room a, Room b)
    {
        // ...
    }
}

Now, I need to use my IRoom child and a RoomComparer child as a generic type parameters for this class:

public class Hotel<TRoom, TComparer> : IHotel, IEnumerable<TRoom> 
    where TRoom : class, IRoom 
    where TComparer : RoomComparer, new()
{
    public List<TRoom> Rooms;
    protected TComparer Comparer;

    public Hotel(int stars, TRoom[] rooms)
    {
        Rooms = new List<TRoom>();
        _stars = stars;
        Rooms.AddRange(rooms);
        Comparer = new TComparer();
        Rooms.Sort(Comparer);
    }

    // ...
}

But compilation fails on line

Rooms.Sort(Comparer);

with two errors

Error CS1502: The best overloaded method match for `System.Collections.Generic.List.Sort(System.Collections.Generic.IComparer)' has some invalid arguments (CS1502)

Error CS1503: Argument #1' cannot convertTComparer' expression to type `System.Collections.Generic.IComparer' (CS1503)

From my point of view, OOP model is correct, and if an argument to Hotel class constructor implements IRoom, just like this: new Hotel<Room, SquareMetersComparer>, than it should be correctly passed to RoomsComparer class constructor and, then, RoomComparer should be correctly passed to a List.Sort() method. But compiler thinks in other way...

So, the question is: what's wrong?

If this helps somehow: I am using Mono 5.10.0 on Ubuntu 14.04.

Upvotes: 0

Views: 161

Answers (2)

Jaap Elgersma
Jaap Elgersma

Reputation: 169

TComparer is defined as inheriting RoomComparer. That means that it implements IComparer of Room. Your list contains instances of TRoom, which implements IRoom, not Room.

Upvotes: 3

Erti-Chris Eelmaa
Erti-Chris Eelmaa

Reputation: 26298

Well first, you need to fix the errors in your SquareMetersComparer and StandardMultipliedSquareMetersComparer class. They are overriding public override int Compare(IRoom a, IRoom b) but they are supposed to override public override int Compare(Room a, Room b).

Secondly, you want to use naked constraints between comparer and TRoom, as such:

where TRoom : class, IRoom 
where TComparer : IComparer<TRoom>, new()

Also, covariance works for IComparer, which means you can also specify such constraints, if necessary:

where TRoom : class, IRoom 
where TComparer : IComparer<IRoom>, new()

Upvotes: 1

Related Questions