2016-07-05 2 views
4

Я сейчас читаю потрясающую книгу Джона Скита «C# in depth (3d version)». Я застрял на p.99, имея дело с отсутствием контравариантности для дженериков.Ограничение дженериков в C# 2

class TestGenericVariance 
{ 
    public static void Main(string[] args) 
    { 
     IComparer<IShape> x =new AreaComparer(); 
     List<Circle> circles = new List<Circle>(); 
     circles.Add(new Circle()); 
     circles.Add(new Circle()); 
     //The following line is invalid, Sort expects IComparer<Circle> 
     circles.Sort(x); 
    } 

    public interface IShape 
    { 

    } 

    public class Circle : IShape 
    { 

    } 

    public class AreaComparer : IComparer<IShape> 
    { 
     public int Compare(IShape x, IShape y) 
     { 
      //No matter, just for the test 
      return 0; 
     } 
    } 
} 

Этот код не работает, потому что метод сортировки ожидает

IComparer<Circle> 

как тип параметра.

Один из работы вокруг предложенной с.99, чтобы сделать AreaComparer класса родовым:

class AreaComparer<T> : IComparer<T> where T : IShape 

А затем изменить необщий AreaComparer вывести из родовых один:

class AreaComparer : AreaComparer<IShape> 

В C# 2, код не компилируется, потому что метод сортировки по кругам все еще ожидает

IComparer<Circle> 

Я что-то пропустил?

Nota: Если я изменяю:

class AreaComparer : AreaComparer<Circle> 

Первая строка кода в главном методе просит сформировать явное преобразование

Спасибо всем за вашу помощь.

+5

На самом деле напишите метод Compare(). Заставьте его работать как для круга, так и для прямоугольника без использования GetType(). И проблема становится намного более очевидной. –

+5

Посмотрите, когда я вернусь домой и попытаюсь понять, что я имел в виду. –

+3

Ты слышал это здесь, люди ... только Джон Скит может понять, что означал Джон Скит! –

ответ

4

Идея заключается в том, что вы делаете AreaComparer родовое как это:

public class AreaComparer<T> : IComparer<T> where T : IShape 
{ 
    public int Compare(T x, T y) 
    { 
     return x.Area.CompareTo(y.Area); 
    } 
} 

Затем, когда вам нужно сортировать, вы построить компаратор с правильным аргументом типа:

circles.Sort(new AreaComparer<Circle>()); 

Обратите внимание, что это что IShape имеет свойство Area (как указано в нижней части p97). Это не в вашем примере кода, и это необходимо для того, чтобы разумно реализовать компаратора.

Часть неродного производного класса была предназначена только для упрощения случаев, когда вы довольны использованием IShape и не хотите повторять это.

+0

Спасибо, ребята (и особенно Джон). Теперь я понимаю ! –

Смежные вопросы