C#3.0语法新特性集合
时间:2011-04-05 来源:辛勤的代码工
隐式类型局部变量
C#3.0提供了一个新的关键字var,使用该关键字,编译器会根据用于初始化局部变量的初始值推断出变量的数据类型。
示例代码:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace TestVar
{
class Program
{
static void Main(string[] args)
{
//定义int数组
int[] intAry = new int[] { 1, 2, 3, 4, 5, 6 };
//var varSet = intAry.Where(x => x > 3);
//执行Linq查询
var varSet = from i in intAry where i > 3 select i;
//遍历查询结果
foreach (var v in varSet)
{
Console.WriteLine(v);
}
//输出varSet的类型名称与命名空间
Console.WriteLine(varSet.GetType().Name);
Console.WriteLine(varSet.GetType().Namespace);
Console.ReadKey();
}
}
}
运行结果如下:
使用隐式类型变量的限制:
1. 隐式类型只能用于方法或属性内局部变量的声明,不能用var来定义返回值、参数的类型或类型的数据成员。
2. 使用var进行声明的局部变量必须在声明时进行赋值,且不能以null为初始值。
隐式类型局部变量最终会产生强类型数据。实际上,编译器在编译时,会为隐式类型局部变量推断出一个数据类型,所以最终的IL代码中,这个变量的类型已经被确定了。
为什么需要隐式类型变量?
主要是为了与Linq查询技术相结合,我们也只有在定义Linq查询返回的数据时才应用使用var关键字。
自动属性
示例代码:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace TestVar
{
class AutoProperty
{
public string Name { get; private set; }
public AutoProperty() { }
}
}
上例中使用自动属性语法为AutoProperty创建了一个名为Name,类型为string的属性。该属性的get方法为public,set方法为private。
扩展方法
扩展方法用于对一个现成类型进行扩展,而不去修改现成类型的源码。
示例代码:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace TestVar
{
public static class Extend
{
//第一个参数指定对String类型进行扩展
public static string ReplaceA(this string str, string destStr)
{
//将大写字母A转换为指定字串
return str.Replace("A", destStr);
}
}
}
上例中对String类型进行扩展,将字串中的大写字母A转换为指定字串。定义时必须注意,扩展方法必须在非泛型静态类中定义,且扩展方法也必须是静态的。使用时,必须导入扩展方法所在的命名空间。
上例的使用方法:"AAAA".ReplaceA("B"); //将大写字母A转换为B
其实扩展方法被编译后,在IL代码中只不过将目标类型上的扩展方法调用转换为了对静态扩展方法的直接调用。
分部方法
C#3.0中扩大了partial关键字使用的范围,我们可以把它应用在方法级别。它允许我们在一个文件中构建方法原型,而在另一个文件中实现。但有诸多限制:
1. 分部方法只可以定义在分部类中。
2. 分部方法必须返回void类型。
3. 分部方法参数不能有out修饰符。
4. 分部方法总是隐式私有的,这个限制比较大,所以分部方法很少使用。
示例语法:
定义:partial void PartialMethod(string str);
实现:partial void PartialMethod(string str) { ...... }
对象初始化器
我们可以使用对象初始化器为对象的初始化工作简化语法。
示例:
class ClassA
{
public int X { get; set; }
public int Y { get; set; }
public ClassA(int x)
{
X = x;
}
}
static void Main(string[] args)
{
//普通类对象初始化,使用对象初始化器为Y赋值
ClassA a = new ClassA(1) { Y = 2 };
//集合的初始化
List<Point> points = new List<Point>
{
new Point { X = 2, Y = 2 },
new Point { X = 3, Y = 3 },
};
Console.ReadKey();
}
匿名类型
有时我们可能需要定义类来封装一些临时数据,但并不需要任何关联的方法、事件和其他自定义功能。这时我们可以使用匿名类型。
所有匿名类型都自动继承System.Object,我们可以在匿名类型对象上调用ToString、GetHashCode、Equals、GetType方法。
示例代码:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace TestVar
{
class Program
{
static void Main(string[] args)
{
//定义两个匿名类型对象,属性名称、值均相同
var firstCar = new { Color = "Red", Name = "BMW" };
var secondCar = new { Color = "Red", Name = "BMW" };
//Object.Equals方法比较两个匿名类型对象是否相等
Console.WriteLine(firstCar.Equals(secondCar));
//使用==操作符比较两个匿名类型对象是否相等
Console.WriteLine(firstCar == secondCar);
//比较两个匿名类型是否同一类型
Console.WriteLine(firstCar.GetType().Name == secondCar.GetType().Name);
Console.ReadKey();
}
}
}
该代码输出如下图:
上例中可看出我们使用Euqals比较两个匿名类型对象返回了true,这是因为编译器重写了匿名类型的Equals方法,比较了匿名类型每一个数据成员的值。但在使用==操作符比较时,却得出了false,这是因为匿名类型没有重载==操作符,所以==操作符比较的是两个对象的引用,而非两个对象的内容。有意思的是,两个匿名类型对象的类型比较返回了true。这说明当两个匿名类型的声明相同时(即相同的属性名称和个数),编译器只会为这两个匿名类型生成同一个匿名类型的定义。
匿名类型的限制:
1. 匿名类型不支持事件、自定义方法、自定义运算符、自定义重写。
2. 匿名类型是隐式封闭的。
3. 匿名类型的实例创建只使用默认构造函数。
4. 匿名类型中还可以包含匿名类型。
何时使用匿名类型:大多在Linq查询时使用。