IComparer <> и наследование классов в C # - PullRequest
2 голосов
/ 07 июля 2011

Есть ли способ реализовать специализированный IComparer для типа базового класса, чтобы дочерний класс мог все еще использовать его для сортировки в определенных коллекциях?

Пример

public class A
{
   public int X;
}

public class B:A
{
   public int Y;
}

public AComparer:IComparer<A>
{
    int Compare(A p1, A p2)
    {
        //...
    }

}

, поэтому будет работать следующий код:

List<A> aList = new List<A>();
aList.Sort(new AComparer());

List<B> bList = new List<B>();
bList.Sort(new AComparer()); // <- this line fails due to type cast issues 

Как подойти к этому вопросу, чтобы иметь как наследование сортировки, так и специализированные коллекции (и не копировать классы IComparer для каждого из дочерних классов?

Заранее спасибо!

1 Ответ

4 голосов
/ 07 июля 2011

Во-первых, обратите внимание, что это исправлено в .NET 4 через универсальную контрастность - ваш код будет просто работать.РЕДАКТИРОВАТЬ: Как отмечалось в комментариях, общая дисперсия была впервые поддержана в CLR v2, но различные интерфейсы и делегаты стали только ковариантными или контравариантными в .NET 4.

Однако в .NET 2 все еще довольно легко создатьконвертер:

public class ComparerConverter<TBase, TChild> : IComparer<TChild>
    where TChild : TBase
{
    private readonly IComparer<TBase> comparer;

    public ComparerConverter(IComparer<TBase> comparer)
    {
        this.comparer = comparer;
    }

    public int Compare(TChild x, TChild y)
    {
        return comparer.Compare(x, y);
    }
}

Затем вы можете использовать:

List<B> bList = new List<B>();
IComparer<B> bComparer = new ComparerConverter<A, B>(new AComparer());
bList.Sort(bComparer);

РЕДАКТИРОВАТЬ: Нет ничего, что вы можете сделать, не изменив способ вызова на всех .Вы можете потенциально сделать ваш AComparer универсальным, хотя:

public class AComparer<T> : IComparer<T> where T : A
{
    int Compare(T p1, T p2)
    {
        // You can still access members of A here
    }    
}

Тогда вы можете использовать:

bList.Sort(new AComparer<B>());

Конечно, это означает, что все ваши реализации компаратора будут универсальными, и это несколько уродливоИМО.

...