协变和逆变

  协变与逆变是.NET 4.O 的新特性,协变和逆变允许数组类型、委托类型和泛型类型参数进行隐式引用转换。 协变保留分配兼容性,逆变与之相反.

  一.协变

   1.介绍概念之前,先看个例子  

    /// <summary>
/// 在.NET 4.0之前编译报错
/// </summary>
class Program
{
public abstract class Person { public string Name { get; set; } }
public class Student : Person {}
public class Teacher : Person { }

static void Main()
{
Student student = new Student();
Person person = student;// 这里,基类指向子类的引用,编译通过
IEnumerable<Student> students = null;
IEnumerable<Person> persons = students;//这里 编译报错
}
}

    在.NET 4.0 赋值操作是有效的,这是因为IEnumerable<T>的定义发生了变化:

public interface IEnumerable<out T> : IEnumerable  //就是这个out关键字起了作用
{
      
IEnumerator<T> GetEnumerator();
}

  就IEnumerable<out T>而言,泛型参数多了个out的定义,就能让泛型与实际的参数类型有相同的兼容性,out关键字编译器会把泛型当成协变。

            Student------------------------------->Person (隐式转换)

        IEnumerable<Student>---------------->IEnumerable<Person>(也能隐式转换)

  但是假设IList<T>也具有协变的特效,就会带来灾难。    

  IList<Student> students = new List<Student>;
  IList<Person> persons = students;  //假设IList定义为 IList<out T>
  persons.Add(new Tearcher());// error1:studens 明确定义了是学生的集合,这里却加入了老师。
  persons[0]=new Tearcher();// error2 : 这里让学生的引用指向了老师。                          

  所以实施协变的重要条件就是只包含输出操作,不会修改泛型参数T,请参考error1,error2.

  二 逆变

   逆变可以理解为与泛型类型参数的隐式转换方向相反,还是看个例子。

public interface IComparable<in T> //in 关键字 表明斜变。
{
bool CompareTo(T other);
}
Student student = null;
Person person = studnet; //子类到父类的隐式转换。
IComparable<Person> icPerson =null;
IComparable<Student> icStudent = icPerson //这里,.NET4.0 中支持 将父类类型的参数接口 赋给 子类类型的参数接口

 类型转换方向                                Student ----------------------------> Person

 逆变参数类型的方向 IComparable<Student> <--------------------------- IComparable<Person>

 可以看出这与类型隐式转换的方向相反,所以称之为“逆”。为什么这里可以用子类赋值给父类,这是因为IComparable<T>含有的方法CompareTo(T other) 接受泛型类型的参数作为输入,对Person的所有操作当然它的子类也具有同样的行为,可以对人类进行比较,当然能对学生进行比较。

  三 注意事项

  1. 协变和逆变都只能针对于泛型的接口和委托,不能针对于类和结构。简单理解就是,委托本身即使一个方法的定义与接口相似,最重要的是都不包含数据成员,因为类可能包含数据成员,对其进行输入和输出操作是不定的,所以类和结构既不支持协变也不支持逆变。

  2. 协变和逆变的参数类型只能是引用类型,不能是值类型。从MSDN上看出,主要的原因是有不必要的内存开销,牵涉到装箱和拆箱操作。

posted @ 2012-04-03 03:25  _小阳  阅读(571)  评论(0编辑  收藏  举报