C#中 Var关键字
Var是C#3.5新增的一个关键字,用来代替某些具体的类型,由编译器自动判断变量类型,编译器可以根据变量的初始化值“推断”变量的类型。
其主要作用有2个:
1.代替具体类型,实现快速编程的隐式类型用法,常见在foreach便历中,实质是VS编译器给我们提供的一个语法糖。
2.和new 一起使用,来实现一个匿名类型,用来代替需要预先创建的实体类,灵活高效。
隐式类型用法:
var a=1;//int a=1;
var b="1";//string a="1";
var c=DateTime.Today;//DateTime c=DateTime.Today;
在定义一个具体类型的变量时,可以利用var来代替实际的真正类型,如上,//前面与后面的代码完全等价,编译器会自动根据后面的变量值的类型帮我们转换成最匹配的类型,属于一个与语法糖。
注意点:
1.无法使用var来定义一个全局变量,只能定义在方法的内部(因为预先不可知,所以预先不可置)
2.不能用来定义函数的签名,包括返回值,参数类别
3.在定义变量的时候,必须先给值,不能为null,也不能只定义不给值。
4.一旦一个变量被定义成var类型,并确定了指定的类型以后,不能再给这个变量其他类型的值。例: var a="1";a=1;(错误:无法将类型“XX”隐式转换成“YY”)
匿名类型用法:
在实际使用过程中,除了代替具体类型的隐式类型外,更重要的使用方式是定义一个匿名类。
1.1
在开发中,我们有时会像下面的代码一样声明一个匿名类:可以看出,在匿名类的语法中并没有为其命名,而是直接的一个new { }就完事了。从外部看来,我们根本无法知道这个类是干神马的,也不知道它有何作用。
var annoyCla1 = new { ID = 10010, Name = "EdisonChou", Age = 25 }; Console.WriteLine("ID:{0}-Name:{1}-Age:{2}", annoyCla1.ID,annoyCla1.Name, annoyCla1.Age);
经过调试运行,我们发现匿名类完全可以实现具名类的效果:
1.2 深入匿名类背后
既然我们发现匿名类可以完全实现具名类的效果,那么我们可以大胆猜测编译器肯定在内部帮我们生成了一个类似具名类的class,于是,我们还是借助反编译工具对其进行探索。通过Reflector反编译,我们找到了编译器生成的匿名类如下图所示:
从上图可以看出:
(1)匿名类被编译后会生成一个[泛型类],可以看到上图中的<>f__AnonymousType0<<ID>j__TPar, <Name>j__TPar, <Age>j__TPar>就是一个泛型类;
(2)匿名类所生成的属性都是只读的,可以看出与其对应的字段也是只读的;
所以,如果我们在程序中为属性赋值,那么会出现错误;
(3)可以看出,匿名类还重写了基类的三个方法:Equals,GetHashCode和ToString;我们可以看看它为我们所生成的ToString方法是怎么来实现的:
实现的效果如下图所示:
1.3 匿名类的共享
可以想象一下,如果我们的代码中定义了很多匿名类,那么是不是编译器会为每一个匿名类都生成一个泛型类呢?答案是否定的,编译器考虑得很远,避免了重复地生成类型。换句话说,定义了多个匿名类的话如果符合一定条件则可以共享一个泛型类。下面,我们就来看看有哪几种情况:
(1)如果定义的匿名类与之前定义过的一模一样:属性类型和顺序都一致,那么默认共享前一个泛型类
var anonymousClass = new { ID = 1, Name = "青水白凡", Time = DateTime.Today };
var anonymousClass1 = new { ID = 2, Name = "青水白凡", Time = DateTime.Today };
Console.WriteLine($"anonymousClass与anonymousClass1类型:{anonymousClass.GetType() == anonymousClass1.GetType()}");
通过上述代码中的最后两行:我们可以判断其是否是一个类型?答案是:True
(2)如果属性名称和顺序一致,但属性类型不同,那么还是共同使用一个泛型类,只是泛型参数改变了而已,所以在运行时会生成不同的类
var anonymousClass = new { ID = 1, Name = "青水白凡", Time = DateTime.Today }; var anonymousClass2 = new { ID = "1", Name = "青水白凡", Time = DateTime.Today };
我们刚刚说到虽然共享了同一个泛型类,只是泛型参数改变了而已,所以在运行时会生成不同的类。所以,那么可以猜测到最后两行代码所显示的结果应该是False,他们虽然都使用了一个泛型类,但是在运行时生成了两个不同的类。
我们刚刚说到虽然共享了同一个泛型类,只是泛型参数改变了而已,所以在运行时会生成不同的类。所以,那么可以猜测到最后两行代码所显示的结果应该是False,他们虽然都使用了一个泛型类,但是在运行时生成了两个不同的类。
(3)如果数据型名称和类型相同,但顺序不同,那么编译器会重新创建一个匿名类
var anonymousClass = new { ID = 1, Name = "青水白凡", Time = DateTime.Today }; var anonymousClass3 = new { ID = 1, Time = DateTime.Today, Name = "青水白凡" };
运行判断结果为:False
通过Reflector,可以发现,编译器确实重新生成了一个泛型类: