隐式类型和对象集合初始化器是在C# 3.0中引入的。
1 隐式类型
var关键字,主要还是编译器根据变量的值来推断其类型。
1.1隐式类型的局部变量
1 class Program 2 { 3 static void Main(string[] args) 4 { 5 var stringvariable="learning hard"; 6 stringvariable=2; 7 } 8 }
其实当你把鼠标放在var上面的时候,还是可以看到其类型的。
使用隐式类型时有一些限制,包括一下几点:
(1)被声明的变量是一个局部变量,不能为字段(包括静态字段和实例字段)。
(2)变量在声明时必须被初始化,因为编译器要根据变量的赋值来推断类型,如果未被初始化,编译器也就无法完成推断了。C#是静态语言,变量类型未知就会出现编译时错误。
(3)变量不能初始化为一个方法组,也不能为一个匿名函数。
(4)变量不能初始化为null,因为null可以隐式地转化为任何引用类型或可空类型,编译器将不能推断出该变量到底为什么类型。
(5)不能用一个正在声明的变量来初始化隐式类型。如以下代码:
string s; var stringvariable=s;
(6)不能用var来声明方法中的参数类型。
其实我个人建议不要在程序中用过多的var,如果能有类型的就指定类型,这样的代码更让别人看懂。
1.2 隐式类型数组
使用var关键字不仅可以创建隐式类型局部变量,还可以创建数组。
1 class Program 2 { 3 static void Main(string[] args) 4 { 5 var intarray=new[]{1,2,3,4} 6 var stringarray=new[]{"hello","learning hard"}; 7 //下面是错误的示范代码 8 var errorarray=new[]{"hello",3}; 9 } 10 }
使用隐式类型的数组时,编译器也必须要能推断出数组的类型。编译器首先会构造一个包含大括号里所有表达式的编译时类型的集合。在这个集合中,如果所有类型都能隐式地转换为唯一的一种类型,则该类型就成为数组的类型;否则,就会出现编译时错误。
2、对象集合初始化器
2.1 对象初始化器
啥都不说,先上代码:
1 class Program 2 { 3 static void Main(string[] args) 4 { 5 Person p = new Person() {Name = "Hong", Age = 25, Weight = 65, Height = 170}; 6 } 7 } 8 9 public class Person 10 { 11 public string Name { get; set; } 12 public int Age { get; set; } 13 public int Weight { get; set; } 14 public int Height { get; set; } 15 }
其实这又是编译器在帮忙,我们不妨用Reflector看一下:
注意:要想用对象初始化器,你必须确保类具有一个无参构造函数。如果你自定了一个有参数的构造函数而把默认的无参构造函数覆盖,就需要重新定义一个无参构造函数。
2.2 集合初始化器
其实原理和上面的对象初始化器一样,可以利用Reflector反编译查看。
1 class Program 2 { 3 static void Main(string[] args) 4 { 5 List<string> newnames=new List<string>{"111","2222","4433"}; 6 } 7 }
3、匿名类型
1 class Program 2 { 3 static void Main(string[] args) 4 { 5 var person = new {Name = "Hong", Age = 12}; 6 Console.WriteLine($"{person.Name}的年龄为:{person.Age}"); 7 8 var persons = new[] 9 { 10 new {Name = "1", Age = 2}, 11 new {Name = "2", Age = 3}, 12 new {Name = "3", Age = 4} 13 14 //如果加入下面这一行,则会编译错误 15 //new {Name="6"} 16 }; 17 int totalAge = persons.Sum(per => per.Age); 18 Console.WriteLine($"所有人的年龄总和为{totalAge}"); 19 Console.ReadKey(); 20 } 21 }
结果为:
从运行结果和匿名类型的代码可知,使用匿名类型可以省略类定义的代码。使用Reflector查看一下反编译的结果: