linq的基本功能是创建操作管道,以及这些操作需要的任何状态,这些操作表示了各种关于数据的
逻辑,如何刷选,如何排序以及如何将不同的数据源联接到一起,当linq查询在"进程内"执行的时候
那些操作通常用委托来表示:
使用linq to object来处理数据的时,经常会出现一个语句包含几个委托的情况,C sharp3 的lambda表达
式在不牺牲可读性的前提下使这一切成为可能,
简而言之:: lamada 表达式 是对linq数据管线中的操作进行表示的一种符合语言习惯的方式:
1:作为委托的lambda表达式:
从许多方面: lamada 表达式都可以看作事实C sharp2的匿名方法的一种演变 ,匿名方法能做的几乎
一切事情都可以用lamada 表达式来完成:
特别是: 捕获的变量在lambda表达式的行为和匿名方法是一样的,从显示的形式来看,两者并不大的区别,
只是lamada 表达式支持许多快捷语法,使它们更易读,更简练:
与匿名方法相似.lamada 表达式有特殊的转换规则,表达式类型的本身并非委托类型,
但它可以通过多种方式隐式或显式地转换一个委托实例:
匿名函数这个术语同时涵盖了匿名方法和lambda表达式---在很多情况下,两者可以使用相同的转换规则:
Func
returnLength = delegate(string text) { return text.Length; };
Console.WriteLine(returnLength("Hello"));
匿名方法是: delegate(string text) { return text.Length; };
也是打算转换成lamabda表达式的部分:
lamada 表达式最冗长的形式是:
(显式类型参数列表) => {语句}; // => 这个东东用来告诉编译器: 我们正在使用一个lambda表达式
Func
returnLength = (string text) => { return text.Length; };
大多数的时候: 可以用一个表达式来表示整个主体,该表达式的值是lamabda的结果:
格式即将变成:
(显式类型的参数列表 => 表达式 )
(string text=>text.length
隐式类型的参数列表
(隐式类型的参数列表) =>表达式:
隐式类型的参数列表就是一个以逗号分隔的名称列表,没有类型,但显式类型和隐式类型的
参数不能混合使用----要么整个列表都是显式类型的,要么全部是隐式类型.除此之外如果有
任何out参数或 ref参数,就只能使用显式类型:
可以继续写成:
(text)=>text.length:
单一参数的快捷语法:
如果 lamada 表达式只需一个参数,而且哪个参数可以隐式(指定)类型,C sharp3就允许省略圆括号:
这种格式的 lamada 表达式是:
参数名 => 表达式
text=>text.length:
//*****: 使用list
对列表进行刷选,排序并设置其他操作:
< list>
谓语匹配的所有的元素:
sort方法获取一个comparision
,对每个元素执行设置的行为:
class FilmFilteringAndSorting
{
class Film
{
public string Name { get; set; }
public int Year { get; set; }
}
static void Main()
{
var films = new List
{
new Film {Name="Jaws", Year=1975},
new Film {Name="Singing in the Rain", Year=1952},
new Film {Name="Some like it Hot", Year=1959},
new Film {Name="The Wizard of Oz", Year=1939},
new Film {Name="It's a Wonderful Life", Year=1946},
new Film {Name="American Beauty", Year=1999},
new Film {Name="High Fidelity", Year=2000},
new Film {Name="The Usual Suspects", Year=1995}
};
#region--Action行为
// < list>
//谓语匹配的所有的元素:
// sort方法获取一个comparision
// ,对每个元素执行设置的行为:
//lamabda表达式
//Action
// film => Console.WriteLine("Name={0}, Year={1}", film.Name, film.Year);
//用委托表达式
Action
{
Console.WriteLine("Name={0}, Year={1}", film.Name, film.Year);
};
//Action
// film => Console.WriteLine("Name={0}, Year={1}", film.Name, film.Year);
//Note: extra lines added for clarity when running
Console.WriteLine("All films");
films.ForEach(print);
Console.WriteLine();
#endregion
Console.WriteLine("Oldies");
films.FindAll(film => film.Year < 1960)
.ForEach(print);
Console.WriteLine();
//用C#2.0委托表达式
Predicate
{
return film.Year < 1960;
};
Console.WriteLine("OldiesC#2.0的委托表达方式");
films.FindAll(filter).ForEach(print);
Console.WriteLine();
Console.WriteLine("Sorted");
films.Sort((f1, f2) => f1.Name.CompareTo(f2.Name));
films.ForEach(print);
Console.WriteLine("SortedC#2.0的委托表达方式");
Comparison
{
return f1.Name.CompareTo(f2.Name);
};
films.Sort(compare);
films.ForEach(print);
}
}
// 记录事件的本质,又记录与它的发送者和实参有关的信息,也就是你熟悉的delegate(object sender ,EventArgs e){...}
static void Log(string title, object sender, EventArgs e)
{
Console.WriteLine("Event: {0}", title);
Console.WriteLine(" Sender: {0}", sender);
Console.WriteLine(" Arguments: {0}", e.GetType());
foreach (PropertyDescriptor prop in
TypeDescriptor.GetProperties(e)) // PropertyDescriptor属性描述符
{
string name = prop.DisplayName;
object value = prop.GetValue(e);
Console.WriteLine(" {0}={1}", name, value);
}
}
static void Main()
{
Button button = new Button();
button.Text = "Click me";
button.Click += (src, e) => Log("Click", src, e);
button.KeyPress += (src, e) => Log("KeyPress", src, e);
button.MouseClick += (src, e) => Log("MouseClick", src, e);
Form form = new Form();
form.AutoSize = true;
form.Controls.Add(button);
Application.Run(form);
}
表达式树:
.net3.5的表达式树提供了一种抽象的方式将一些代码表示成一个对象树,只适用于表达式,表达式树主要在
linq中使用:
C#3对于将lamabda表达式转化成表达式树提供了内建的支持,但在讨论这个问题之前,首先
应理解在没有使用任何编译器技术的情况下,它们是如何与.net framwork 融合为一体的:
///
// 一个非常简单的表达式的树
class FirstExpressionTree
{
static void Main()
{
Expression firstArg = Expression.Constant(2);
Expression secondArg = Expression.Constant(3);
Expression add = Expression.Add(firstArg, secondArg);
Console.WriteLine(add);
}
}
//编译并执行一个表达树:
// Expression 与LambdaExpression
// 什么种类的表达式,也就是说她确定了返回类型和参数,很明显,这用是TDelegate类型参数来表示的,它必须
// 是一个委托类型 ,
static void Main()
{
Expression firstArg = Expression.Constant(2);
Expression secondArg = Expression.Constant(3);
Expression add = Expression.Add(firstArg, secondArg);
// Func
Func
Console.WriteLine(compiled());
}
//首先表达式树只能表示单一的表达式,她们不能表示完整的类,方法甚至语句,其次,C#通过lamabda表达式直接在语言中支持表达式树:
// 用lambda表达式创建表达式树:
//注意,并不是所有的lambda表达式可以转换成表达式树
class LambdaExpressionToExpressionTree
{
static void Main()
{
Expression
Func
Console.WriteLine(compiled());
}
}
//较为复杂的表达式树:
class LambdaExpressionWithParametersToExpressionTree
{
static void Main()
{
Expression
var compiled = expression.Compile();
Console.WriteLine(compiled("First", "Second"));
Console.WriteLine(compiled("First", "Fir"));
}
}
//较为复杂的表达式树:
class LambdaExpressionWithParametersToExpressionTree
{
static void Main()
{
Expression
var compiled = expression.Compile();
Console.WriteLine(compiled("First", "Second"));
Console.WriteLine(compiled("First", "Fir"));
}
}
//用代码构造一个方法调用表达式树:
//C虽然C#3编译器在编译好的代码中会使用与代码清单9-10相似的代码来构造表达式树
class MethodCallExpressionTree
{
static void Main()
{
MethodInfo method = typeof(string).GetMethod("StartsWith", new[] { typeof(string) });
var target = Expression.Parameter(typeof(string), "x");
var methodArg = Expression.Parameter(typeof(string), "y");
Expression[] methodArgs = new[] { methodArg };
// 以上代码:构造方法调用一个表达式树:
Expression call = Expression.Call(target, method, methodArgs); //以上部件创建调用表达式call
var lambdaParameters = new[] { target, methodArg };
var lambda = Expression.Lambda
var compiled = lambda.Compile(); //将call转换成lambda表达式
Console.WriteLine(compiled("First", "Second"));
Console.WriteLine(compiled("First", "Fir"));
}
}
// 总结lamada表达式提供了编译时检查的能力,而表达树将执行模型从你所需的逻辑中提取出来:
// linq to object 和linq to sql
// linq to object是含有lamada表达式的C#查询代码-->C#编译器-->使用 委托的IL--->委托直接在CLR执行--->查询结果
// linq to sql 是含有lamada表达式的C#查询代码-->C#编译器-->使用表达树的IL--->LINQ TO SQL provider-->动态SQL--->在数据库处执行并取回结果----查询结果:
//----类型推断与重载决策发生的改变:以下代码C3#能通过,而C#不行的:
//C#2的类型推断规则是单独针对每一个实参来进行的,没有办法将从一个实参推断出来的类型直接用于另一个实参:
class ConversionWithTypeInference
{
static void PrintConvertedValue
(TInput input, Converter
{
Console.WriteLine(converter(input));
}
static void Main()
{
PrintConvertedValue("I'm a string", x => x.Length);
}
}
// 展示了貌似能编译,但不符合C#2类型判断规则的一些示例代码
class ReturnTypeInference
{
delegate T MyFunc
static void WriteResult
{
Console.WriteLine(function());
}
static void Main()
{
WriteResult(delegate { return 5; }); // // C#3比起C#2的巨大改变:所有方法的实参在C#3中是以"团队"的形式来工作的:
//两个解决的办法:
//a:要么显式指定类型的实参(就象编译器推荐的那样)
WriteResult
// 将匿名方法强制转换为一个具体的委托类型:
WriteResult((MyFunc
}
class OverloadingByDelegateReturnType
{
static void Execute(Func
{
Console.WriteLine("action returns an int: " + action());
}
static void Execute(Func
{
Console.WriteLine("action returns a double: " + action());
}
static void Main()
{
Execute(() => 1); //用委托lamada表达式转换成func
//在C#2中是会有错误的:
//但在C#3中最终会选中参数为func
// 如果一个匿名函数能转换成参数列表相同,但返回类型不同的两个委托类型,就根据从
//"推断的返回类型"到"委托的返回类型"的转换来判定那个委托转换"更好"
}
}
}
}