dynamic、var、object 这三个是c# 代码中常用的关键字,其中的区别和联系不搞明白的话确实容易混淆
object
支持 .NET 类层次结构中的所有类,并为派生类提供低级别服务。 这是所有 .NET 类的最终基类;它是类型层次结构的根。
通常类都是隐式继承Object。
object类型和其他值类型之间的转换称之为装箱和拆箱操作,
装箱:将值类型转换成引用类型,
拆箱:将引用类型转换成值类型。
装箱和取消装箱类型的过程会带来额外的性能开销。所以实际开发中应该多使用泛型来规避装箱拆箱操作。
装箱示例:
[TestClass]
public class DynamicUnitTest
{
[TestMethod]
public void Convert()
{
int a = 100;
object to = a;
}
}
看下 IL代码
IL_0000: nop
IL_0001: ldc.i4.s 100
IL_0003: stloc.0
IL_0004: ldloc.0
IL_0005: box [System.Runtime]System.Int32 //这里的box就是装箱操作
IL_000a: stloc.1
IL_000b: ret
拆箱示例
[TestClass]
public class DynamicUnitTest
{
[TestMethod]
public void Convert()
{
object a = 100;
int to = (int)a;
}
}
看下IL代码
IL_0000: nop
IL_0001: ldc.i4.s 100
//先执行装箱操作 目的是为了将数字1 int转换为object
IL_0003: box [System.Runtime]System.Int32
IL_0008: stloc.0
IL_0009: ldloc.0
//执行拆箱操作 目的是将object转换成int
IL_000a: unbox.any [System.Runtime]System.Int32
IL_000f: stloc.1
IL_0010: ret
如果将变量a的赋值改为string类型的
object a = "100";
string to = (string)a;
再看看IL代码
IL_0000: nop
IL_0001: ldstr "100"
IL_0006: stloc.0
IL_0007: ldloc.0
//这里没有装箱和拆箱操作 只有castclass 类型转换操作 因为string也是引用类型,而不是值类型
IL_0008: castclass [System.Runtime]System.String
IL_000d: stloc.1
IL_000e: ret
再看看 var
var 和 js中的var作用是一样的,定义一个变量的类型,不需要明确定义类型是什么,编译器在源码编译期间根据变量的赋值自己识别类型,并直接改写替换成实际需要的类型;其本质就是个语法糖。
比如
var a = 100;
看IL代码
.maxstack 1
.locals init (
[0] int32 a
)
IL_0000: nop
IL_0001: ldc.i4.s 100
IL_0003: stloc.0
IL_0004: ldloc.0
locals 定义的类型直接就是 int型
dynamic
编程语言划分为静态类型语言和动态类型语言。C#和Java经常被认为是静态类型的语言,而Python、JavaScript是动态类型语言。一般动态语言在编译时不会对类型进行检查,编写随意,而是在运行时识别对象的类型。而静态语言,在编写时就对类型进行了严格的检查。
dynamic是FrameWork4.0的新特性。dynamic的出现让C#具有了弱语言类型的特性。编译器在编译的时候不再对类型进行检查,编译期默认dynamic对象支持你想要的任何特性,但是他在IL中的类型到底是什么,是怎么实现这些特性的?
比如
dynamic a = 100;
int s = a + 1;
看下IL代码
.locals init (
[0] object a, //dynamic直接就换成了object
[1] int32 s
)
// (no C# code)
IL_0000: nop
// dynamic val = 100;
IL_0001: ldc.i4.s 100
IL_0003: box [System.Runtime]System.Int32 //object类型的变量a 的赋值是值类型的,所以产生了装箱操作
IL_0008: stloc.0
由此可以看出dynamic本质上就是个object类型,只不过在写源代码的时候不再进行类型检查,从而减少了类型转换的操作,实现了动态语言的特征。
所以总结下来
用var请随意 ,符合代码规范即可;
object和dynamic使用的时候 要注意装箱和拆箱操作,尽量使用泛型规避;
网友评论