Lambda的表达式:()=>{}
Lambda的本质:一个匿名函数,在底层,会在一个尖括号(<>)类中,生成带有名称的方法。
Linq的本质(代码的封装思想):从技术上说:是通过扩展方法来完成的,从程序设计上说:把不变的业务逻辑转移,固定的业务逻辑封装,整合起来就是Linq。
2.Lambda的前世今生
.NetFramework2.0 匿名方法 增加了一个delegate关键字,可以访问到除了参数以外的局部变量
.NetFramework3.0 去掉delegate关键了,在参数的后增加了一个=> goes to
.NetFramework3.0后期,去掉了匿名方法红的参数类型,编译器提供了语法糖,可以推导出类型的参数
namespace MyLambdaLinq
public delegate void NoReturnNoParaOutClass();
public delegate void GenericDelegate<T>();
public class LambdaShow
public delegate void NoReturnNoPara();
public delegate void NoReturnWithPara(int x, string y);
public delegate int WithReturnNoPara();
public delegate string WithReturnWithPara(out int x, ref int y);
public void Show()
int j = 0;
NoReturnNoPara method = new NoReturnNoPara(DoNothing);
NoReturnWithPara method1 = new NoReturnWithPara(Study);
method1.Invoke(123, "HelloWord");
int i = 0;
NoReturnWithPara method = new NoReturnWithPara(delegate (int x, string y)
Console.WriteLine(x);
Console.WriteLine(y);
Console.WriteLine(i);
NoReturnWithPara method = new NoReturnWithPara((int x, string y) =>
Console.WriteLine(x);
Console.WriteLine(y);
Console.WriteLine(i);
NoReturnWithPara method = new NoReturnWithPara((x, y) =>
Console.WriteLine(x);
Console.WriteLine(y);
Console.WriteLine(i);
NoReturnWithPara method = new NoReturnWithPara((x, y) => Console.WriteLine(x));
NoReturnWithPara method1 = (x, y) => Console.WriteLine(x);
private void DoNothing()
Console.WriteLine("This is DoNothing");
private void Study(int id, string name)
Console.WriteLine($"Id:{id},Nam: {name}");
二、匿名类
Object:因为C#是强类型语言,Object需要在编译时才能确定类型。
--定义的字段无法被调用
dynamic:可以避开编译器的检查。
--定义的字段可以被调用
--调用没有定义的字段在运行前也不会出异常
--可给字段重新赋值。
var:弱类型,编译时确定类型。
--定义的字段可以被调用
--调用的字段没有定义的话会出现异常
--无法给字段重新赋值
--无法声明方法
--无法赋值为null,必须进行初始化赋值,且赋的值必须让能推算出类型。
--不允许作为方法的参数的类型使用
(建议var使用场景:需要使用到匿名类的时候,在不确定具体什么类型的时候,复杂类型的时候。缺点是:代码可读性变差,开发中建议尽量明确类型)
三、扩展方法
扩展:扩充,让现有的功能更强大,增加原本不存在的功能
扩展方法:在不修改原有类的情况下,增加一个新的方法,并且可以像实例方法一样调用。
扩展方法需要满足的条件:
1.必须是静态类中的静态方法
2.扩展的是谁,谁就要作为第一个参数,且这个参数前面需要增加this关键字
应用场景:
1.扩展第三方类库,第三方类库多是引用dll方式引入,无法直接修改代码,可以使用扩展方法给第三方类库增加新功能。
2.祖传项目维护,本着老代码能不动就不动的原则(老代码一般补丁代码过多,可能修改一个地方就会导致其他地方出现问题),使用扩展方法进行新功能增加。
1.普通的扩展方法
现有的一个学生类:
public class Student
public int Age { get; set; }
public string Name { get; set; }
public void Study()
Console.WriteLine($"{Age}岁的{Name}在这里是学习");
定义一个扩展类:
此处的StudentExtension为静态方法,StudyMore方法的参数前增加了this关键字
public static class StudentExtension
public static void StudyMore( this Student student)
Console.WriteLine($"{student.Age}岁的{student.Name}这里是学习更多");
static void Main(string[] args)
Student student = new Student();
student.Name = "张三";
student.Age = 23;
student.Study();
student.StudyMore();
执行结果:
2.类型的扩展方法(建议使用时指定具体类型进行扩展)
1.普通类型都可以进行方法扩展,示例中的IntToString()方法
2.泛型可以进行方法扩展。但是具有侵入性(表示所有的类型都会拥有这个方法,覆盖面太广),可能会导致一些类型存在了一些不应该存在的行为,如果使用错误便会导致bug发生,如示例3。
3.Object是所有类型的父类,所有也会出现泛型的问题。
4.如果版本升级导致dll等引用中,增加了扩展方法,同时也在类的内部增加了一个同样的方法,在调用的时候,会优先调用类内部声明的方法;
演示用的扩展类:
public static class ExtensionMethod
public static string IntExtension(this int i)
return i.ToString();
public static string GenericsExtension<T>(this T t)
return t.ToString();
public static int GenericsExtension2<T>(this T t)
return Convert.ToInt32(t);
public static string ObjectExtension(this Object o)
return o.ToString();
调用演示:
static void Main(string[] args)
int i = 0;
i.IntExtension();
i.GenericsExtension<int>();
string s = "传入字符换类型之后这个方法将会报错";
s.GenericsExtension2<string>();
i.ObjectExtension();
3.实战演示
如果字符串长度超过5,就只取前五个字符
public static class ExtensionMethod
public static string ToSubString(this string str, int maxLength = 5)
if (string.IsNullOrEmpty(str))
return string.Empty;
if (str.Length > maxLength)
return str.Substring(0, 5);
return str;
调用演示:
static void Main(string[] args)
string str1 = "这是六个字哦";
Console.WriteLine($"字符串大于五个字的时候:{str1.ToSubString()}");
string str2 = "这是五个字";
Console.WriteLine($"字符串等于五个字的时候:{str2.ToSubString()}");
string str3 = "这字";
Console.WriteLine($"字符串小于五个字的时候:{str3.ToSubString()}");
string str4 = "";
Console.WriteLine($"字符串为空的时候:{str4.ToSubString()}");
执行结果:
四、Linq的原理及示例
Linq to Object:通过方法封装+不变的逻辑封装在方法中,可变的逻辑通过委托传递+扩展方法
Linq to sql:把不变的逻辑封装在内,可变的sql语句通过委托传递
Linq to xml:把不变的处理xml的逻辑封装在内,可变的处理xml的逻辑通过委托传递
1.使用[扩展方法+委托]模拟Linq的原理
与linq中where的区别: linq的底层是通过迭代器实现循环的
技术手段来说:通过拓展方法来完成的
扩展方法:
public static class ExtensionMethod
#region Test1
#endregion
public static List<Student> FilteringStudentData(this List<Student> studentList, Func<Student, bool> func)
List<Student> stuList = new List<Student>();
foreach (var stu in studentList)
if (func.Invoke(stu))
stuList.Add(stu);
return stuList;
public static List<T> FilteringData<T>(this List<T> old_List, Func<T, bool> func)
List<T> list = new List<T>();
foreach (var item in old_List)
if (func.Invoke(item))
list.Add(item);
return list;
static void Main(string[] args)
List<Student> list = new List<Student>()
new Student()
Name = "张三",
Age = 18
new Student()
Name = "李四",
Age = 17
new Student()
Name = "王二",
Age = 19
Func<Student, bool> func = new Func<Student, bool>(s =>
return s.Age < 18;
var student = list.FilteringStudentData(func);
var stu = list.FilteringStudentData(s => s.Age < 18);
var stu_linq = list.Where(s => s.Age < 18);
2.改造方法更接近Linq(IEnumerable+yieId)
扩展IEnumerable,使用yieId(状态机的实现)关键字(yieId必须和IEnumerable配套使用)
----IEnumerable通常认为是一个内存数据,类似的还有IQueryable
----yieId关键字做到了按需获取,判断时,只要符合条件就返回,如果不返回就继续往后判断
扩展方法:
public static class ExtensionMethod
public static IEnumerable<T> Where_YieId<T>(this IEnumerable<T> old_List, Func<T, bool> func)
foreach (var item in old_List)
if (func.Invoke(item))
yield return item;
static void Main(string[] args)
List<Student> list = new List<Student>()
new Student()
Name = "张三",
Age = 18
new Student()
Name = "李四",
Age = 17
new Student()
Name = "王二",
Age = 19
IEnumerable<Student> stuList = list.Where_YieId(s => s.Age < 18);
foreach (var item in stuList)
Console.WriteLine($"名字:{item.Name},年龄:{item.Age}");
五、Linq常见的语句
除以下常用示例外,关于Linq的文档:Linq相关文档(阿里云盘)
static void Main(string[] args)
List<Student> list = new List<Student>()
new Student()
Name = "张三",
Age = 18,
Class = "一班"
new Student()
Name = "李四",
Age = 17,
Class = "二班"
new Student()
Name = "王二",
Age = 19,
Class = "一班"
#region Linq的两种方式
var stuList1 = list.Where
x => x.Age > 18
).ToList();
foreach (var item in stuList1)
Console.WriteLine($"stuList1结果展示:Name:{item.Name},Age:{item.Age}");
var stuList2 = from s in list
where s.Age > 18
select s;
foreach (var item in stuList2)
Console.WriteLine($"stuList2结果展示:Name:{item.Name},Age:{item.Age}");
#endregion
#region Linq to Object
#region 投影
var list1 = list
.Where(
x => x.Age > 18
.Select(s => new
people = s.Name + "-" + s.Age,
describe = s.Age > 18 ? "成年人" : "未成年人"
foreach (var item in list1)
Console.WriteLine($"list1结果展示:people:{item.people},describe:{item.describe}");
var list2 = from s in list
where s.Age > 18
select new
people = s.Name + "-" + s.Age,
describe = s.Age > 18 ? "成年人" : "未成年人"
foreach (var item in list2)
Console.WriteLine($"list2结果展示:people:{item.people},describe:{item.describe}");
#endregion
#region 过滤、排序
var list3 = list
.Where(
x => x.Age > 18
.Select(s => new
people = s.Name + "-" + s.Age,
describe = s.Age > 18 ? "成年人" : "未成年人",
Age = s.Age
.OrderBy(s => s.Age)
.ThenBy(s => s.describe)
.OrderByDescending(s => s.Age)
.Skip(2)
.Take(3)
foreach (var item in list3)
Console.WriteLine($"list3结果展示:people:{item.people},describe:{item.describe}");
#endregion
#region 分组
var list4 = from s in list
where s.Age > 18
group s by s.Class into g
select new
Class = g.Key,
MaxAge = g.Max(s => s.Age)
foreach (var item in list4)
Console.WriteLine($"list4结果展示:Class:{item.Class},MaxAge:{item.MaxAge}");
var list5 = list.GroupBy(s => s.Class).Select(x => new
Class = x.Key,
MaxAge = x.Max(x => x.Age)
foreach (var item in list5)
Console.WriteLine($"list5结果展示:Class:{item.Class},MaxAge:{item.MaxAge}");
#endregion
#region join、left join连接查询
var list6 = from s in list
join c in stuList1 on s.Class equals c.Class
select new
Name = s.Name,
Age = s.Age,
Class = s.Class
foreach (var item in list6)
Console.WriteLine($"list6结果展示:Name:{item.Name},Class:{item.Class}");
var list7 = list.Join(stuList1, s => s.Class, c => c.Class, (s, c) => new
Name = s.Name,
Age = s.Age,
Class = s.Class
foreach (var item in list7)
Console.WriteLine($"list7结果展示:Name:{item.Name},Class:{item.Class}");
var list8 = from s in list
join c in stuList1 on s.Class equals c.Class into g
from x in g.DefaultIfEmpty()
select new
Name = s.Name,
Age = s.Age,
Class = s.Class,
describe = x == null ? "没有该班级" : "有该班级"
foreach (var item in list8)
Console.WriteLine($"list8结果展示:Name:{item.Name},Class:{item.Class}");
var list9 = list.Join(stuList1, s => s.Class, c => c.Class, (s, c) => new
Name = s.Name,
Age = s.Age,
Class = s.Class,
describe = c == null ? "没有该班级" : "有该班级"
}).DefaultIfEmpty();
foreach (var item in list9)
Console.WriteLine($"list9结果展示:Name:{item.Name},Class:{item.Class}");
#endregion
#endregion
复制代码