13.3.2 在接口中使用可变性

1. 用 in 和 out 表示可变性

我们使用的两个接口是 IEnumerable<T> (对于 T 是协变的)和 IComparer<T> (对于 T 是逆变的),它们可以很好地展示可变性。以下是它们在.NET 4中的声明:

    public interface IEnumerable<out T>
    public interface IComparer<in T>

这非常好记:如果类型参数只用于输出,就使用 out ;如果只用于输入,就用 in 。编译器可不知道你是否记住了哪种形式是协变,哪种形式是逆变。

 1     public interface IShape
 2     {
 3         double Area { get; }
 4 
 5         System.Windows.Rect BoundingBox { get; }
 6     }
 7     /// <summary>
 8     /// WindowsBase.dll下
 9     /// </summary>
10     public sealed class Circle : IShape
11     {
12         private readonly System.Windows.Point center;
13         public System.Windows.Point Center { get { return center; } }
14 
15         private readonly double radius;
16         public double Radius { get { return radius; } }
17 
18         public Circle(System.Windows.Point center, int radius)
19         {
20             this.center = center;
21             this.radius = radius;
22         }
23 
24         public double Area
25         {
26             get { return Math.PI * radius * radius; }
27         }
28 
29         public System.Windows.Rect BoundingBox
30         {
31             get
32             {
33                 return new System.Windows.Rect(center - new System.Windows.Vector(radius, radius), new System.Windows.Size(radius * 2, radius * 2));
34             }
35         }
36     }
37     public sealed class Square : IShape
38     {
39         private readonly Point topLeft;
40         private readonly double sideLength;
41 
42         public Square(Point topLeft, double sideLength)
43         {
44             this.topLeft = topLeft;
45             this.sideLength = sideLength;
46         }
47 
48         public double Area { get { return sideLength * sideLength; } }
49 
50         public Rect BoundingBox
51         {
52             get { return new Rect(topLeft, new Size(sideLength, sideLength)); }
53         }
54     }
View Code

2. 接口的协变性

 1             List<Circle> circles = new List<Circle>()
 2             {
 3                 new Circle(new Point(0, 0), 15),
 4                 new Circle(new Point(10, 5), 20),
 5             };
 6             List<Square> squares = new List<Square>()
 7             {
 8                 new Square(new Point(5, 10), 5),
 9                 new Square(new Point(-10, 0), 2),
10             };
11 
12             List<IShape> shapesByAdding = new List<IShape>();
13             shapesByAdding.AddRange(circles);
14             shapesByAdding.AddRange(squares);
15             List<IShape> shapesByConcat = circles.Concat<IShape>(squares).ToList();

实际上,代码清单13-12在4个地方使用了协变性,对于类型系统而言,每次将圆形或方形序列转换为普通几何形状时,都用到了协变性。
首先新建了一个 List<IShape> ,并调用 AddRange向其添加圆形和方形列表 。(我们也可以向构造函数传递一个列表,然后调用 AddRange 一次。)
List<T>.AddRange 的参数为 IEnumerable<T> 类型,因此在这种情况下我们将这两个列表都看成是 IEnumerable<IShape> ,而这在以前是不被允许的。

3. 接口的逆变性

 1     class Program
 2     {
 3         static void Main(string[] args)
 4         {
 5             List<Circle> circles = new List<Circle>()
 6             {
 7                 new Circle(new Point(0, 0), 15),
 8                 new Circle(new Point(10, 5), 20),
 9             };
10             List<Square> squares = new List<Square>()
11             {
12                 new Square(new Point(5, 10), 5),
13                 new Square(new Point(-10, 0), 2),
14             };
15 
16             IComparer<IShape> areaComparer = new AreaComparer();
17             circles.Sort(areaComparer);
18         }
19     }
20     class AreaComparer : IComparer<IShape>
21     {
22         public int Compare(IShape x, IShape y)
23         {
24             return x.Area.CompareTo(y.Area);
25         }
26     }
原文地址:https://www.cnblogs.com/kikyoqiang/p/10105698.html