Got stuck trying to sort my List<>
in C#.
I have an interface type with its implementation class:
public interface IRoom
{
// ...
}
public class Room : IRoom
{
// ...
}
And a base class for my comparers:
public abstract class RoomComparer : IComparer<IRoom>
{
public RoomComparer()
{
}
public abstract int Compare(IRoom x, IRoom y);
}
And two its children:
public class StandardMultipliedSquareMetersComparer : RoomComparer
{
public StandardMultipliedSquareMetersComparer()
{
}
public override int Compare(IRoom a, IRoom b)
{
// ...
}
}
public class SquareMetersComparer : RoomComparer
{
public SquareMetersComparer()
{
}
public override int Compare(IRoom a, IRoom b)
{
// ...
}
}
Now, here's where the problems begin: I got a generic class Hotel
with a list of my Room
instances:
public class Hotel<TRoom, TComparer> : IHotel, IEnumerable<TRoom>
where TRoom : IRoom
where TComparer : RoomComparer, new()
{
public List<TRoom> Rooms;
protected TComparer Comparer;
public Hotel(TRoom[] rooms)
{
Rooms = new List<TRoom>();
Rooms.AddRange(rooms);
Comparer = new TComparer();
Rooms.Sort(Comparer);
}
}
And here's the trouble - I got two errors on the line Rooms.Sort(Comparer);
:
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 convert
TComparer' expression to type `System.Collections.Generic.IComparer' (CS1503)
I tried many different solutions, but no result. What's happening?
Note: using Mono 3.10.0
on Ubuntu
You're trying to use generic contravariance for this (if a comparer can compare two TRoom
values, it should be able to compare two IRoom
values), which would usually be fine - but only when TRoom
is known to be a class type. You can fix that by requiring that TRoom
is a reference type:
where TRoom : class, IRoom
At that point, contravariance works fine, and all is well. It does require that all your room types are genuinely classes, of course.
Do you definitely need the hotel to be generic like this? It seems a little too much like overkill to me...
See more on this question at Stackoverflow