C#3.0语言层面的增强
主要有以下几点:
隐含类型局部变量
扩展方法
对象与集合初始化器
匿名类型
Lambda表达式
查询表达式( LINQ )
表达式树
隐含类型局部变量
var i = 5;
var h=23.56;
var s = “C Sharp";
var intArr = new[] {1,2,3,4} ;
var a = new[] { 1, 10, 100, 1000 };// int[]
var 为关键字,可以根据后面的初始化语句自动推断类型
初始化语句必须为表达式,且编译时可以推断类型。
var声明的仅限于局部变量,亦可以用于foreach,using 等语句中
数组也可以作为隐含类型。
using System;
using System.Collections.Generic;
using System.Collections;
using System.Linq;
using System.Text;
namespace varForeach
{
class varForeach
{
static void Main(string[] args)
{
string[] names = new string[] { "a","b","c"};
varForeachShow(names);
}
public static void varForeachShow<C>(C collection) where C : IEnumerable //还可以继承ICollection
{
foreach(var c in collection)
{
Console.WriteLine(c.ToString());
}
}
}
}
扩展方法
public static class Extensions{
public static void Foo(this string s) {
…..
}
}
String s=“Hello,World”;
s.Foo(); //最终编译器会转换成这样的代码:Extensions.Foo(s);
扩展方法允许我们在不改变源代码的情况下扩展(即添加)现有类型中的实例方法。
class Person
{
public void DoSth(){}
}
Person p = new Person; p.DoSth();
编译器会产生类似的代码
DoSth(Person this){}
Person p = new Person;
DoSth(p);
扩展方法
扩展方法的本质为将实例方法调用在编译期改变为静态类中的静态方法调用。
注意扩展方法的优先级:现有实例方法优先级最
高,其次为最近的namespace下的静态类的静态方
法,最后为较远的namespace下的静态类的静态方
法。
扩展方法是一种编译时技术,注意与反射等运行时技术进行区别,并慎重使用
扩展方法其实是一种二进制的扩展
静态类中不要加入多于一个类型的扩展方法
对象与集合初始化器
对象初始化器:
public class Point {
int x, y;
public int X { get { return x; } set { x = value; } }
public int Y { get { return y; } set { y = value; } }
}
var a = new Point { X = 0, Y = 1 };
相当于:var a = new Point(); a.X = 0; a.Y = 1;
集合初始化器:
List<int> num= new List<int> { 0, 1, 2, 6, 7, 8, 9 };
对象与集合初始化器要点
对象初始化器的原始类型要有一个公有的无参的构造函数
对象初始化器实际上利用了编译器对对象中对外可见的字段和属性进行按序赋值。
集合初始化器会对初始化器中的元素进行按序调用ICollection<T>.Add(T) 。
注意对象初始化器和集合初始化器中成员的可见性和调用顺序。
对象与集合初始化器同样是一种编译时技术。
匿名类型
var p1 = new { Name = "Lawnmower", Price = 495.00 }
var p2 = new { Name = "Shovel", Price = 26.95 };
p1 = p2;
可以使用new关键字调用匿名初始化器创建一个匿名类型的对象。
匿名类型直接继承自System.Object。
匿名类型的成员是编译器根据初始化器推断而来的一些读写属性。
Lambda表达式
第一个lambada表达式
static void Main(string[] args)
{
List<string> list = new List<string> { "asdf","rew","nfaf" };
List<string> resultList = list.FindAll(a => a.IndexOf('a') >= 0);
string[] listStrings = resultList.ToArray(); //将list中的元素复制到新数组中
foreach (var s in listStrings)
{
Console.WriteLine(s);
}
}
.net1.1时代委托实现:
static void Main(string[] args)
{
List<string> list = new List<string> { "adf", "barfe", "rewrq" };
Predicate<string> pre = new Predicate<string>(IsHave);
List<string> resultList = list.FindAll(pre);
string[] resultStrings = resultList.ToArray();
foreach (var s in resultStrings)
{
Console.WriteLine(s);
}
}
public static bool IsHave(string s)
{
return s.IndexOf('f') >= 0;
}
.net 2.0时代匿名方法实现版本
static void Main(string[] args)
{
List<string> list = new List<string> { "adf", "barfe", "rewrq" };
List<string> resultList = list.FindAll(
delegate(string s)
{
return s.IndexOf('a') >= 0;
}
);
string[] resultStrings = resultList.ToArray(); //将resultList中元素复制到新数组resultStrings中
foreach (var s in resultStrings)
{
Console.WriteLine(s);
}
}
net3时代lamabda表达式实现版本
static void Main(string[] args)
{
List<string> list = new List<string> { "adf", "barfe", "rewrq" };
List<string> stringList = list.FindAll(s => s.IndexOf('a') >= 0);
string[] resultStrings = stringList.ToArray();
foreach (var s in resultStrings)
{
Console.WriteLine(s);
}
}
lambda表达式试图做的是用人的语言来描述需求,list.FindAll(s => s.IndexOf(‘f’)>0);表达式在说我要在s中看看字符f的索引是不是大于0
问题是编译器是否能从这个表达式正确的推断出,你是要new 一个委托:Predicate<string> pre = new Predicate<string>(IsHave);并且写一个方法,方法的功能是s.IndexOf(‘f’)>0
编译器先从list.FindAll方法的参数要求的委托上推断出方法的签名,(Predicate<string>)在本例中方法要求一个string类型参数,并且返回值为bool的方法,接着从上面的lambada表达式发现正有一个参数是s,有一个表达式返回bool,但参数的类型lambada表达式并没有给出,在此例中可以从list本身所包含项的类型做出合理推断,s为string类型,一切OK
Lambda表达式格式
Lambda表达式格式为:(参数列表)=>表达式或者语句块
可以有多个参数,一个参数,或者无参数。参数类型可以隐式或者显式。例如:
(x, y) => x * y //多参数,隐式类型=> 表达式
x => x * 10 //单参数, 隐式类型=>表达式
x => { return x * 10; } //单参数,隐式类型=>语句块
(int x) => x * 10 // 单参数,显式类型=>表达式
(int x) => { return x * 10; } // 单参数,显式类型=>语句块
() => Console.WriteLine() //无参数
Lambda表达式格式要点
Lambda表达式的参数类型可以忽略,因为可以根据使用的上下文进行推断。
Lambda表达式的主体(body)可以是表达式,也可以是语句块。
Lambda表达式传入的实参将参与类型推断,以及方法重载辨析。
Lambda表达式和表达式体可以被转换为表达式树。
Lambda表达式与委托类型
Lambda表达式L可以被转换为委托类型D,需要满足以下条件:
L和D拥有相同的参数个数。
L的参数类型要与D的参数类型相同。注意隐式类型要参与类型辨析。
D的返回类型与L相同,无论L是表达式,还是语句块。