zoukankan      html  css  js  c++  java
  • c# 协变和逆变

    由子类向父类方向转变是协变,用out关键字标识,由父类向子类方向转变是逆变,用in关键字
     

    协变和逆变的应用

     

    一、 数组的协变

     

    Animal[] animalArray = new Dog[]{};
     
    说明:声明的数组数据类型是Animal,而实际上赋值时给的是Dog数组;每一个Dog对象都可以安全的转变为Animal。Dog向Animal方法转变是沿着继承链向上转变的所以是协变
     
     
    二. 委托中的协变和逆变
     
     
    1、委托中的协变
     
    C# 代码   复制
    
    
    //委托定义的返回值是Animal类型是父类
    
    public delegate Animal GetAnimal();
    
    //委托方法实现中的返回值是Dog,是子类
    
    static Dog GetDog(){return new Dog();}
    
    //GetDog的返回值是Dog, Dog是Animal的子类;返回一个Dog肯定就相当于返回了一个Animal;所以下面对委托的赋值是有效的
    
    GetAnimal getMethod = GetDog;
    

     

    2、委托中的逆变

     
    C# 代码   复制
    
    
    //委托中的定义参数类型是Dog
    
    public delegate void FeedDog(Dog target);
    
    //实际方法中的参数类型是Animal
    
    static void FeedAnimal(Animal target){}
    
    // FeedAnimal是FeedDog委托的有效方法,因为委托接受的参数类型是Dog;而FeedAnimal接受的参数是animal,Dog是可以隐式转变成Animal的,所以委托可以安全的的做类型转换,正确的执行委托方法;
    
    FeedDog feedDogMethod = FeedAnimal;
    //定义委托时的参数是子类,实际上委托方法的参数是更宽泛的父类Animal,是父类向子类方向转变,是逆变
    

     

    三. 泛型委托的协变和逆变

     

    1、 泛型委托中的逆变

     
    C# 代码   复制
    
    //委托声明:
    
    public delegate void Feed<in T>(T target); 
    
    //Feed委托接受一个泛型类型T,注意在泛型的尖括号中有一个in关键字,这个关键字的作用是告诉编译器在对委托赋值时类型T可能要做逆变
    
    
    //先声明一个T为Animal的委托
    
    Feed<Animal> feedAnimalMethod = a=>Console.WriteLine(“Feed animal lambda”);
    
    //将T为Animal的委托赋值给T为Dog的委托变量,这是合法的,因为在定义泛型委托时有in关键字,如果把in关键字去掉,编译器会认为不合法
    
    Feed<Dog> feedDogMethod = feedAnimalMethod; 
    

     

    2、泛型委托中的协变

     
    C# 代码   复制
    
    //委托声明
    
    public delegate T Find<out T>(); 
    
    //Find委托要返回一个泛型类型T的实例,在泛型的尖括号中有一个out关键字,该关键字表明T类型是可能要做协变的
    
    //声明Find<Dog>委托
    
    Find<Dog> findDog = ()=>new Dog();
    
    //声明Find<Animal>委托,并将findDog赋值给findAnimal是合法的,类型T从Dog向Animal转变是协变
    
    Find<Animal> findAnimal = findDog; 
    

     

    四. 泛型接口中的协变和逆变

     

    1、泛型接口中的逆变

     
    C# 代码   复制
    
    //接口定义:
    
    public interface IFeedable<in T>
    {
    
    void Feed(T t);
    
    } 
    
    
    //接口的泛型T之前有一个in关键字,来表明这个泛型接口可能要做逆变
    
    //如下泛型类型FeedImp<T>,实现上面的泛型接口;需要注意的是协变和逆变关键字in
    
    
    public class FeedImp<T>:IFeedable<T>
    {
    
        public void Feed(T t){
    
            Console.WriteLine(“Feed Animal”);
    
        }
    
    } 
    
    
    //使用接口逆变:
    
    IFeedable<Dog> feedDog = new FeedImp<Animal>(); 
    
    //上面的代码将FeedImp<Animal>类型赋值给了IFeedable<Dog>的变量;Animal向Dog转变了,所以是逆变
    

     

    2、泛型接口中的协变

     
    C# 代码   复制
    
    //接口的定义:
    
    public interface IFinder<out T> 
    {
        T Find();
    } 
    
    
    //泛型接口的泛型T之前用了out关键字来说明此接口是可能要做协变的;如下泛型接口实现类
    
    public class Finder<T>:IFinder<T> where T:new()
    {
        public T Find(){
            return new T();
        } 
    }  
    
    
    //使用协变,IFinder的泛型类型是Animal,但是由于有out关键字,我可以将Finder<Dog>赋值给它
    
    IFinder<Animal> finder = new Finder<Dog>(); 
    
  • 相关阅读:
    BEM(Block–Element-Modifier)
    http://element.eleme.io/#/zh-CN/component/quickstart
    Commit message 的写法规范。本文介绍Angular 规范(
    好的commit应该长啥样 https://github.com/torvalds/linux/pull/17#issuecomment-5654674
    代码管理
    if you have content fetched asynchronously on pages where SEO is important, SSR might be necessary
    Martin Fowler’s Active Record design pattern.
    The Zen of Python
    Introspection in Python How to spy on your Python objects Guide to Python introspection
    Object-Oriented Metrics: LCOM 内聚性的度量
  • 原文地址:https://www.cnblogs.com/rr163/p/4047404.html
Copyright © 2011-2022 走看看