2.1 委托的使用
能够解耦&代码重用
public void SayHi(string name,SayHiDelegate method){
//公共方法.....
method.Invoke(name);
//公共方法....
}
多波委托拆解后的异步调用
public delegate void TestFun();
static void Main(string[] args) {
//多播委托
TestFun testFun = new TestFun(() => Console.WriteLine("Hello World"));
testFun += new TestFun(() => Console.WriteLine("Hello World"));
testFun+= new TestFun(() => Console.WriteLine("Hello World"));
testFun.Invoke();
//多播委托无法进行异步调用,可通过此方法进行拆解
foreach (TestFun item in testFun.GetInvocationList()) {
item.BeginInvoke(null,null);
}
}
}
2.2 Lambda
参数列表=>方法体,Lambda表达式就是一个匿名方法,就是一个方法。
基于lambda表达式注册的多播委托是无法移除的。
2.2.1 发展过程
public void delegate SayHiDelegate(string name);
public void SayHi(string name){
Console.WriteLine($"Say Hi,{name}");
}
//.NET Framework1.0
SayHiDelegate sayHi = new SayHiDelegate(this.SayHi);
sayHi.Invoke("Albert");
//.NET Framework2.0 匿名方法
SayHiDelegate sayHi = new SayHiDelegate(delegate (string name){
Console.WriteLine($"Say Hi,{name}");
});
sayHi.Invoke("Albert");
//.NET Framework3.0 delegate变为=>
//lambda参数类型可以推断出来,可省略。根据委托的约束来推断出的。 语法糖
SayHiDelegate sayHi = new SayHiDelegate(name =>{
Console.WriteLine($"Say Hi,{name}");
});
sayHi.Invoke("Albert");
//如果方法体只有一行,可以省略大括号+分号 语法糖
SayHiDelegate sayHi = new SayHiDelegate(name =>
Console.WriteLine($"Say Hi,{name}")
);
sayHi.Invoke("Albert");
//实例化委托时,可以省略new SayHiDelegate 语法糖
SayHiDelegate sayHi = name =>
Console.WriteLine($"Say Hi,{name}");
sayHi.Invoke("Albert");
2.2.2 对Lambda用于表达式目录树进行解析
解析类
ConditionBuilderVistor.cs ConditionBuilderVisitor.cs
SqlOperator.csSqlOperator.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;
namespace MyDelegateEvent.ExpressionTest
{
public class ConditionBuilderVisitor : ExpressionVisitor
{
private Stack<string> _StringStack = new Stack<string>();
public string Condition()
{
string condition = string.Concat(this._StringStack.ToArray());
this._StringStack.Clear();
return condition;
}
/// <summary>
/// 二元表达式
/// </summary>
/// <param name="node"></param>
/// <returns></returns>
protected override Expression VisitBinary(BinaryExpression node)
{
if (node == null) throw new ArgumentNullException("BinaryExpression");
this._StringStack.Push(")");
base.Visit(node.Right);//解析右边
this._StringStack.Push(" " + node.NodeType.ToSqlOperator() + " ");
base.Visit(node.Left);//解析左边
this._StringStack.Push("(");
return node;
}
/// <summary>
///
/// </summary>
/// <param name="node"></param>
/// <returns></returns>
protected override Expression VisitMember(MemberExpression node)
{
if (node == null) throw new ArgumentNullException("MemberExpression");
this._StringStack.Push(" [" + node.Member.Name + "] ");
return node;
}
/// <summary>
/// 常量表达式
/// </summary>
/// <param name="node"></param>
/// <returns></returns>
protected override Expression VisitConstant(ConstantExpression node)
{
if (node == null) throw new ArgumentNullException("ConstantExpression");
this._StringStack.Push(" '" + node.Value + "' ");
return node;
}
/// <summary>
/// 方法表达式
/// </summary>
/// <param name="m"></param>
/// <returns></returns>
protected override Expression VisitMethodCall(MethodCallExpression m)
{
if (m == null) throw new ArgumentNullException("MethodCallExpression");
string format;
switch (m.Method.Name)
{
case "StartsWith":
format = "({0} LIKE {1}+'%')";
break;
case "Contains":
format = "({0} LIKE '%'+{1}+'%')";
break;
case "EndsWith":
format = "({0} LIKE '%'+{1})";
break;
default:
throw new NotSupportedException(m.NodeType + " is not supported!");
}
this.Visit(m.Object);
this.Visit(m.Arguments[0]);
string right = this._StringStack.Pop();
string left = this._StringStack.Pop();
this._StringStack.Push(String.Format(format, left, right));
return m;
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;
namespace MyDelegateEvent.ExpressionTest
{
internal static class SqlOperator
{
internal static string ToSqlOperator(this ExpressionType type)
{
switch (type)
{
case (ExpressionType.AndAlso):
case (ExpressionType.And):
return "AND";
case (ExpressionType.OrElse):
case (ExpressionType.Or):
return "OR";
case (ExpressionType.Not):
return "NOT";
case (ExpressionType.NotEqual):
return "<>";
case ExpressionType.GreaterThan:
return ">";
case ExpressionType.GreaterThanOrEqual:
return ">=";
case ExpressionType.LessThan:
return "<";
case ExpressionType.LessThanOrEqual:
return "<=";
case (ExpressionType.Equal):
return "=";
default:
throw new Exception("不支持该方法");
}
}
}
}
使用:
{
var userDbSet = new List<Student>().AsQueryable();
var userList = userDbSet.Where(s => s.Id > 100 && s.Name.Contains("1"));
Expression<Func<Student, bool>> predicate = s => s.Id > 100
&& s.Name.Contains("1")
&& s.Name.StartsWith("2")
&& s.Name.EndsWith("3")
&& s.QQ > 57265177
&& s.QQ < 999999999;
{
//把predicate转成一个where 子句
ConditionBuilderVisitor visitor = new ConditionBuilderVisitor();
visitor.Visit(predicate);
string where = visitor.Condition();
}
}
2.3 LINQ的代码实现
Linq to object(Enumerable):数据源是内存里面的集合—传递的委托判断
Linq to sql(Queryable):数据源在SqlServer—需要Sql语句—从表达式目录树而来的(2.2.2有从表达式目录树转为Sql语句)
自我实现1,通过委托来传递逻辑,来实现List全遍历。
查看源码发现,LINQ的Where是通过迭代器来实现的,重新优化实现逻辑,实现方式通过IEnumerable来进行yield迭代输出:按需获取、延时加载。(发生迭代)需要才进入检查。
迭代器方法的内部使用状态机实现,但可以使用yield关键字快速实现迭代器方法,使用yield return语句添加需要迭代的元素,在首次迭代时,会一直执行到第一个yield return语句并保存当前迭代状态,在接下来的每次迭代过程中都会从暂停的位置继续执行到下一个yield return语句并保存迭代状态(MoveNext()方法返回true并将当前迭代的值赋值给Current),直到到达迭代器的结尾(MoveNext()方法返回false)完成本次迭代;也可以在迭代过程中使用yield break语句立刻结束本次迭代
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace LINQComple {
class Program {
static void Main(string[] args) {
List<Student> students = new List<Student>();
for (int i = 0; i < 30; i++) {
students.Add(new Student() { Age = 28 + i, Name = "Albert_" + i.ToString() });
}
Console.WriteLine("***************Start 这是系统方法*************");
var list = students.Where(s => {
Thread.Sleep(100);
return s.Age > 29;
}); //LINQ
foreach (var item in list) {
Console.WriteLine(item.Name);
}
Console.WriteLine("***************End 这是系统方法*************");
Console.WriteLine("***************Start 这是自定义方法1*************");
var list2 = students.AlbertWhere(s => {
Thread.Sleep(100);
return s.Age > 29;
});
foreach (var item in list2) {
Console.WriteLine(item.Name);
}
Console.WriteLine("***************End 这是自定义方法*************");
Console.WriteLine("***************Start 这是自定义方法2*************");
var ienm = students.AlbertWhereIEnumber(s => {
Thread.Sleep(100);
return s.Age > 29;
});
foreach (var item in ienm) {
Console.WriteLine(item.Name);
}
Console.WriteLine("***************End 这是自定义方法2*************");
}
}
/// <summary>
/// 自己通过委托实现Linq查询
/// if中不同的逻辑需要传递,相当于告诉你要使用委托
/// 1.基于委托封装,完成代码复用
/// </summary>
public static class LinqExtend {
public static List<T> AlbertWhere<T>(this List<T> ts,Func<T, bool> func) {
List<T> ts1 = new List<T>();
foreach (var item in ts) {
if (func.Invoke(item)) {
ts1.Add(item);
}
}
return ts1;
}
/// <summary>
/// 通过枚举迭代,和LINQ原理相同,不会一直在等待查询全部完毕
/// 迭代器升级:按需获取、延时加载。(发生迭代)需要才进入检查
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="ts"></param>
/// <param name="func"></param>
/// <returns></returns>
public static IEnumerable<T> AlbertWhereIEnumber<T>(this IEnumerable<T> ts,Func<T,bool> func) {
foreach (var item in ts) {
if (func.Invoke(item)) {
yield return item;
}
}
}
}
public class Student {
public int Age { get; set; }
public string Name { get; set; }
}
}