小寒的blog
Programming is a darned hard thing—but I am going to like it.

先看个例子,此代码在c# 4.0下可以编译通过,因为c#4.0才开始支持逆变和协变

 

代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApplication1
{
 
    
class Program
    {
        
public static void Main()
        {

            IEnumerable
<object> objs = new List<string>(); //协变

            Action
<object> action1 = o => { };

            Action
<string> action2 = action1;//逆变
        }
    }
}

 

下面是泛型接口IEnumerable<T>相关类型的定义

   

代码
 public interface IEnumerable<out T> : IEnumerable
    {
        
// Summary:
        
//     Returns an enumerator that iterates through the collection.
        
//
        
// Returns:
        
//     A System.Collections.Generic.IEnumerator<T> that can be used to iterate through
        
//     the collection.
        IEnumerator<T> GetEnumerator();
    }

    
public interface IEnumerator<out T> : IDisposable, IEnumerator
    {
        
// Summary:
        
//     Gets the element in the collection at the current position of the enumerator.
        
//
        
// Returns:
        
//     The element in the collection at the current position of the enumerator.
        T Current { get; }
    }

 

 

可以看到T在IEnumerable定义中比以前多了out的修饰符。out表示T在泛型类型中只能被用作输出。也就是说T定义的对象是只会被用作赋值给客户代码中的引用。这样凡是使用IEnumerable<BaseType>类型的地方都可以被安全的替换成IEnumerable<SubType>.因为子类型(SubType)可以安全替换父类型(BaseType)

下面是泛型委托Action<T>的定义

 

   public delegate void Action<in T>(T obj);

这里是用in修饰T。说明T在泛型中只会被用作输入,也就是说T定义的引用只能用作接受客户代码的赋值。所以使用Action<SubType>的地方都可以被安全的替换成Acton<BaseType>.道理和上面一样子类型(SubType)可以安全替换父类型(BaseType)。

 

总结:协变和逆变允许我们定义的泛型接口和泛型委托能更加的通用。而且保证不会破坏类型安全。

posted on 2010-06-01 11:21  xhan  阅读(541)  评论(0编辑  收藏  举报