【C#】var、对应具体类型、object性能比较

概述

var关键字是.net3.5推出的关键字,主要是让编译器自动推断并判断变量类型,类似javascript中的var。

在使用一些性能优化软件时,在代码优化时,我发现不管定义什么类型的变量,变量的类型都统统换成var。难道var的性能比具体的类型和object都要高?

var

var可声明局部变量而无需提供显式类型。 var 关键字指示编译器通过初始化语句右侧的表达式推断变量的类型。 推断类型可以是内置类型、匿名类型、用户定义类型或 .NET 类库中定义的类型。

以下限制适用于隐式类型化变量声明:

  • 仅当局部变量在相同语句中进行声明和初始化时,才能使用 var;变量不能初始化为 null,也不能初始化为方法组或匿名函数。
  • var 不能在类范围内对字段使用。
  • 使用 var 声明的变量不能在初始化表达式中使用。 换句话说,此表达式是合法的:int i = (i =
    20);,但是此表达式会生成编译时错误:var i = (i = 20);
  • 不能在相同语句中初始化多个隐式类型化变量。
  • 如果一种名为 var 的类型处于范围内,则 var 关键字会解析为该类型名称,不会被视为隐式类型化局部变量声明的一部分。

带 var 关键字的隐式类型只能应用于本地方法范围内的变量。

object

object关键字相当于Object类的别名,参考string和String

支持 .NET 类层次结构中的所有类,并为派生类提供低级别服务。 这是所有 .NET 类的最终基类;它是类型层次结构的根。

语言通常不需要类来声明继承 Object ,因为继承是隐式的。

由于 .NET 中的所有类都派生自 Object,因此 Object 类中定义的每个方法都可用于系统中的所有对象。 派生类可以替代其中一些方法,包括:

  • Equals - 支持对象之间的比较。
  • Finalize - 在自动回收对象之前执行清理操作。
  • GetHashCode - 生成与对象值对应的数字,以支持使用哈希表。
  • ToString - 制造描述类实例的可读文本字符串。

性能注意事项
如果要设计必须处理任何类型的对象的类(如集合),则可以创建接受类实例的 Object 类成员。 但是,装箱和取消装箱类型的过程会产生性能成本。 如果你知道新类经常处理某些值类型,则可以使用两种策略之一来最大程度地降低装箱成本。

  • 创建一个接受 Object 类型的常规方法,以及一组特定于类型的方法重载,这些重载接受你期望类经常处理的每个值类型。
    如果存在接受调用参数类型的特定于类型的方法,则不会发生任何装箱,并且调用特定于类型的方法。
    如果没有与调用参数类型匹配的方法参数,则会对参数进行装箱,并调用常规方法。
  • 设计类型及其成员以使用泛型。 公共语言运行时在创建类的实例并指定泛型类型参数时,会创建一个封闭的泛型类型。
    泛型方法特定于类型,无需装箱调用参数即可调用。

虽然有时有必要开发接受和返回 Object 类型的常规用途类,但还可以提供特定于类型的类来处理常用类型,从而提高性能。 例如,提供特定于设置和获取布尔值的类可消除装箱和取消装箱布尔值的成本。

实践出真知

新建一个控制台应用程序

class Program {
        static void Main(string[] args) {

            for (int i = 0; i < 10; i++)
            {
                Test();
                Console.WriteLine();
            }

          

            Console.Read();
        }


        public static void Test()
        {

            Stopwatch stw = new Stopwatch();
            Stopwatch stw1 = new Stopwatch();
            Stopwatch stw2 = new Stopwatch();


            /*Object性能测试 */
            stw2.Start();//开始时间

            List<int> intlist3 = new List<int>();
            for( int i = 0; i < 10000000; i++ ) {
                object index = i;//使用object转入和转出
                intlist3.Add((int)index);
            }
            stw2.Stop();
            Console.WriteLine("obj:{0}", stw2.Elapsed.Ticks);


            /*Var 性能测试 */


            List<int> intlist = new List<int>();
            stw1.Start();
            for( int i = 0; i < 10000000; i++ ) {
                var index = i;//使用var转入和转出
                intlist.Add(index);
            }
            stw1.Stop();

            Console.WriteLine("Var:{0}", stw1.Elapsed.Ticks);

            /*Int 性能测试 */


            List<int> intlist2 = new List<int>();
            stw.Start();//重新开始计时
            for( int i = 0; i < 10000000; i++ ) {
                int index = i;//使用int转入和转出
                intlist2.Add(index);
            }
            stw.Stop();

            Console.WriteLine("int:{0}", stw.Elapsed.Ticks);

            
        }

    }

测试结果:
在这里插入图片描述
分析:

通过查阅文档和书籍,var是隐式类型的局部变量 主要是方便书写。在编译期间,早已把var替换为实际推断的类型(这里是int),而object多了一个装箱拆箱的操作,耗时自然是最长的。

以下是笔者对程序进行反编译(C# 和 IL)后的截图,我们可以清晰滴看到多余的代码已经被优化,而所谓的var也不见了。在IL源码中,明显的看到object在循环的时候有装箱拆箱的操作。

反编译的C#代码:(已经被优化)
在这里插入图片描述
object测试的IL:
在这里插入图片描述
var测试的IL:
在这里插入图片描述
int测试的IL:
在这里插入图片描述

总结

var性能 ≈ int > object

object 类型牵涉装箱拆箱的问题,自然是效率最慢的。

但从测试结果来看,var类型的性能与int不相上下,但在测试结果中可以看到大部分var耗时会超过int。 实际上var在编译的时候已经确定类型了

来源

C# 中 var、int、object 性能比较 (已修正)
Object 类
隐式类型本地变量(C# 编程指南)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

软泡芙

给爷鞠躬!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值