欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Net 如何计算一段代码的效率

程序员文章站 2022-06-25 18:42:50
在.Net 4.0以后的版本,提供了一个类,该类在 System.Diagnostics命名空间下,使用该类就可以计算出执行结果相同的两端代码的效率,在代码优化上是很实用的。 泛型效率是高是低呢??我们来测试下,代码如下: 经过上述执行,我们可以把我们程序框架里面的帮助类都改成泛型的。 ......

首先声明,本文写的有点粗糙,只让你了解什么是协变和逆变,没有深入研究,根据这些年的工作经验,发现我们在开发过程中,很少会自己去写逆变和协变,因为自从net 4.0 (Framework 3.0) 以后,.net 就为我们提供了 定义好的逆变与协变。我们只要会使用就可以。协变和逆变都是在泛型中使用的。

  • 什么是逆变与协变呢

 

可变性是以一种类型安全的方式,将一个对象当做另一个对象来使用。如果不能将一个类型替换为另一个类型,那么这个类型就称之为:不变量。协变和逆变是两个相互对立的概念:

 

  • 如果某个返回的类型可以由其派生类型替换,那么这个类型就是支持协变
  • 如果某个参数类型可以由其基类替换,那么这个类型就是支持逆变的。

 

看起来你有点绕,我们先准备个“”鸟”类,在准备一个“麻雀”类,让麻雀继承鸟类,一起看代码研究

 

  /// <summary>
    /// 鸟
    /// </summary>
    public class Bird
    {
        public int Id { get; set; }
    }
    /// <summary>
    /// 麻雀
    /// </summary>
    public class Sparrow : Bird
    {
        public string Name { get; set; }
    }

 

 我们分别取实例化这个类,发现程序是能编译通过的。

Bird bird1 = new Bird();
Bird bird2 = new Sparrow();
Sparrow sparrow1 = new Sparrow();

  //Sparrow sparrow2 = new Bird();//这个是编译不通过的,违反了继承性。

但是我们放在集合中,去实例化,是无法通过的

List<Bird> birdList1 = new List<Bird>();

//List<Bird> birdList2 = new List<Sparrow>();//不是父子关系,没有继承关系
//一群麻雀一定是一群鸟

 那么我们如何去实现在泛型中的继承性呢??这就引入了协变和逆变得概念,为了保证类型的安全,C#编译器对使用了 out 和 in 关键字的泛型参数添加了一些限制:

  • 支持协变(out)的类型参数只能用在输出位置:函数返回值、属性的get访问器以及委托参数的某些位置
  • 支持逆变(in)的类型参数只能用在输入位置:方法参数或委托参数的某些位置中出现。
  • 协变

  我们来看下Net  “System.Collections.Generic”命名空间下的IEnumerable泛型 接口,会发现他的泛型参数使用了out 

Net 如何计算一段代码的效率

现在我们使用下 IEnumerable  接口来进行一下上述实力,会发现,我们的泛型有了继承关系。

IEnumerable<Bird> birdList1 = new List<Bird>();

IEnumerable<Bird> birdList2 = new List<Sparrow>();//协变
//一群麻雀一定是一群鸟

下面我们来自己定义一个协变泛型接口ICustomerListOut<Out T>,让 CustomerListOut 泛型类继承CustomerListOut<Out T> 泛型接口。

代码如下

    /// <summary>
    /// out 协变 只能是返回结果
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public interface ICustomerListOut<out T>
    {
        T Get();

       // void Show(T t);//T不能作为传入参数
    }

    /// <summary>
    /// 类没有协变逆变
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public class CustomerListOut<T> : ICustomerListOut<T>
    {
        public T Get()
        {
            return default(T);
        }

        public void Show(T t)
        {

        }
    }

 我们会发现,在泛型斜变的时候,泛型不能作为方法的参数。我们用自己定义的泛型接口和泛型类进行实例化试试,我们会发现编译通过

ICustomerListOut<Bird> customerList1 = new CustomerListOut<Bird>();//这是能编译的
ICustomerListOut<Bird> customerList2 = new CustomerListOut<Sparrow>();//这也是能编译的,在泛型中,子类指向父类,我们称为协变

到这里协变我们就学完了,协变就是让我们的泛型有了子父级的关系。本文开始的时候,协变和逆变,是在C# 4.0 以后才有的,那C# 4.0以前我们是怎么写的呢,那个时候没有协变?

老版本的写法

  List<Bird> birdList3 = new List<Sparrow>().Select(c => (Bird)c).ToList();//4.0以前的写法

等学完逆变,本文列出C# 4.0 以后的版本 中framework 已经定义好的协变、逆变 泛型接口,泛型类,泛型委托。

  • 逆变

 刚才我们学习了泛型参数用out 去修饰,饺子协变,现在来学习下逆变,逆变是使用in来修饰的

这里就是Net 4.0 给我们提供的逆变写法

Net 如何计算一段代码的效率

我们自己写一个逆变的接口  ICustomerListIn<in T> ,在写一个逆变的 泛型类 CustomerListIn<T>:ICustomerListIn<T> ,代码如下

    /// <summary>
    /// 逆变
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public interface ICustomerListIn<in T>
    {
        //T Get();//不能作为返回值

        void Show(T t);
    }

    public class CustomerListIn<T> : ICustomerListIn<T>
    {
        public T Get()
        {
            return default(T);
        }

        public void Show(T t)
        {
        }
    }

 

 逆变的泛型参数是不能作为泛型方法的返回值的,我们来看下实例化鸟类,和麻雀类,看好使不好使。

ICustomerListIn<Sparrow> customerList2 = new CustomerListIn<Sparrow>();
ICustomerListIn<Sparrow> customerList1 = new CustomerListIn<Bird>();//父类指向子类,我们称为逆变

ICustomerListIn<Bird> birdList1 = new CustomerListIn<Bird>();
birdList1.Show(new Sparrow());
birdList1.Show(new Bird());

Action<Sparrow> act = new Action<Bird>((Bird i) => { });

 到此我们就完全学完了逆变与协变

 

  • 总结

逆变与协变只能放在泛型接口和泛型委托的泛型参数里面,

在泛型中out修饰泛型称为协变,协变(covariant  修饰返回值 ,协变的原理是把子类指向父类的关系,拿到泛型中。
 在泛型中in 修饰泛型称为逆变, 逆变(contravariant )修饰传入参数,逆变的原理是把父类指向子类的关系,拿到泛型中。

  • NET 中自带的斜变逆变泛型

 序号  类别  名称
 1  接口  IEnumerable<out T> 
 2 委托  Action<in T>
3 委托 Func<out TResult>
 4  接口 IReadOnlyList<out T> 
 5  接口 IReadOnlyCollection<out T>
     

 各位朋友,如果谁还知道,请留言告知