.NET中的逆变协变

  MSDN上的说法:

IEnumerable(Of Base))的实例。

  感觉MSDN说的还是有些拗口。  

in 关键字。

  简单来说就是假设有一个泛型逆变接口IDo<in T>,有两个可以替换T的类型A和B时,B如果继承自A时,可以将IDo<A>的实例赋值给IDo<B>,例如:

  

private void button1_Click(object sender, EventArgs e)
{

  IDo<A> a = new DoT<A>();
  IDo<B> b = new DoT<B>();

  Run run = new Run();
  run.Set<D>(a);
}

 

interface IDo<in T>
{
  void Do(T t);

}

class A { }
class B : A { }
class D : B { }
class C : A { }
class E : C { }

class DoT<T> : IDo<T>
{
  public void Do(T t)
  {
    MessageBox.Show(t.GetType().ToString());
  }
}

class Run
{
  public void Set<T>(IDo<T> it) where T : new()
  {
    it.Do(new T());//返回D的类型
    MessageBox.Show(it.GetType().ToString());//返回A的接口类型
  }
}

  协变:Covariance,类型使用out关键字。

  这个相对于逆变来说更容易理解,当有接口IDo<out T>时,有两个可以替换T的类型A和B时,B如果继承自A时,可以将IDo<B>的实例赋值给IDo<A>,说这更容易理解是因为里氏替换大家会熟悉些,这个看起来有些像,不过不要混淆,这是两回事,例子:

    interface IDo<out T>
    {
        T get();
    }    

    private void button1_Click(object sender, EventArgs e)
    {
        IDo<A> a = new DoT<A>();
        IDo<B> b = new DoT<B>();

        Run run = new Run();
        run.Set<A>(b);
    }

  另外需要注意的,使用了in的T只能用做输入参数,不能用做返回值。使用了out做参数的只能用做返回值,不能做输入参数。

  我曾经写过一个随笔,实现中使用了协变的特性:由继承演变为角色扮演