C#之LINQ学习笔记
程序员文章站
2022-07-04 08:47:06
...
C#之LINQ学习笔记
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace Linq
{
class Program
{
delegate void NoReturnNoPara();//无返回值无参数委托类型
delegate void NoReturnWithPara(int x, int y);//无返回值有参数委托类型
delegate int WithReturnWithPara(int x, int y);//有返回值有参数委托类型
static void Main(string[] args)
{
LambdaShow();//Lambda表达式
AnonymousClassShow();//匿名类
ExtendFunc();//扩展方法
LinqShow();//Linq方法
Console.ReadKey();
}
#region 基础知识
/// <summary>
/// Lambda表达式
/// </summary>
static void LambdaShow()
{
{//委托的实例化
NoReturnNoPara method = new NoReturnNoPara(Dothing);
method.Invoke();
}
{//匿名方法
NoReturnNoPara method = new NoReturnNoPara(delegate ()
{
Console.WriteLine("This is Dothing");
});
method.Invoke();
}
{//Lambda 左边是参数列表,中间=>是goes to,有边是方法体,本质是一个方法
NoReturnNoPara method = new NoReturnNoPara(() =>
{
Console.WriteLine("This is Dothing");
});
method.Invoke();
}
{//带参数
NoReturnWithPara method = new NoReturnWithPara((int x, int y) =>
{
Console.WriteLine("This is Dothing");
});
method.Invoke(1, 2);
}
{//带参数,省略参数类型
NoReturnWithPara method = new NoReturnWithPara((x, y) =>
{
Console.WriteLine("This is Dothing");
});
method.Invoke(1, 2);
}
{//方法体只有一行时可以省略大括号
NoReturnWithPara method = new NoReturnWithPara((x, y) => Console.WriteLine("This is Dothing"));
method.Invoke(1, 2);
}
{//实例委托时可以省略:new NoReturnWithPara,编译器自动推算
NoReturnWithPara method = ((x, y) => Console.WriteLine("This is Dothing"));
method.Invoke(1, 2);
}//Lambda表达式是什么?
//首先不是委托,委托是类型
//然后也不是委托的实例,因为这里省略new 委托()
//它的作用和方法是一样的
//它的实质是一个类中类的internal方法,被绑定的一个静态的委托类型字段
{
NoReturnWithPara Method = new NoReturnWithPara((x, y) => Console.WriteLine("This is Dothing"));
Method += new NoReturnWithPara((x, y) => Console.WriteLine("This is Dothing"));
Method -= new NoReturnWithPara((x, y) => Console.WriteLine("This is Dothing"));
Method.Invoke(1, 2);//会执行两次,-=无法去掉已经注册的方法,以为new创建的两个对象虽然相同,但不是同一个
}
}
/// <summary>
/// 匿名类
/// </summary>
static void AnonymousClassShow()
{
//匿名类
object oModel = new
{
Id = 2,
Name = "undefined",
Age = 25,
ClassId = 2
};
//Console.WriteLine(oModel.Id);object编译器不允许,无法直接访问,通过反射访问
Type oType = oModel.GetType();
PropertyInfo propertyInfo = oType.GetProperty("Id");
Console.WriteLine(propertyInfo.GetValue(oModel));
//propertyInfo.SetValue(oModel, 3);//匿名类是只读,无法写入
dynamic dModel = new//dynamic可以避开编译器的检查,可以直接访问
{
Id = 2,
Name = "undefined",
Age = 25,
ClassId = 2
};
//dModel.Id = 3;//实例是只读,所以不能赋值
Console.WriteLine(dModel.Id);
var varModel = new//编译后是有一个真实的类,可以直接访问,但类的字段都是只读
{
Id = 2,
Name = "undefined",
Age = 25,
ClassId = 2
};
//varModel.Id = 3;//实例是只读,所以不能赋值
Console.WriteLine(varModel.Id);
int i2 = 2;
var i1 = 1;//var是语法糖,由编译器自动推算类似
var ss = "superman";
//var aa;//var必须在声明的时候就确定类型
//ss = 123;//确定类型后不能更改
//var、object和dynamic的区别:
//var是推算出来的类型,可能是任意一种类型。
//object是一种确定的类型,它是所有类型的基类
//dynamic是一个复杂类型,在编译的时候不知道它是什么类型,它只是避开编译器检查,如果失败就会报错。
}
/// <summary>
/// 扩展方法
/// </summary>
static void ExtendFunc()
{
Student student = new Student()
{
Id = 1,
ClassId = 1,
Name = "xiaoming",
Age = 22,
};
student.Study();
student.StudyHard();
//又要增加方法,又不能修改类时,采用扩展方法,使用别人的库文件时
student.Sing();//调用扩展方法
ExtendMethod.Sing(student);//普通的调用静态方法
//泛型扩展方法
student.ExtendShow();
//重复扩展方法,编译无错,调用错误:二义性
//没有扩展属性,partial类可以扩展属性
//int? 可空类型
int? iValue1 = null;
int? iValue = 2;
int value=iValue1.ToInt();
int length = iValue.Length();
}
static void Dothing()
{
Console.WriteLine("This is Dothing");
}
#region Linq
#region Data Init
/// <summary>
/// 构造一个Student类对象的List
/// </summary>
/// <returns></returns>
public static List<Student> GetStudentList()
{
List<Student> list = new List<Student>()
{
new Student
{
Id=1,
ClassId=1,
Name="xiaoming",
Age=24
},
new Student
{
Id=2,
ClassId=2,
Name="xiaofang",
Age=34
},
new Student
{
Id=3,
ClassId=3,
Name="xiaohua",
Age=33
},
new Student
{
Id=4,
ClassId=4,
Name="xiaojia",
Age=27
},
new Student
{
Id=5,
ClassId=5,
Name="xiaocheng",
Age=33
},
new Student
{
Id=6,
ClassId=6,
Name="xiaofu",
Age=27
},
};
return list;
}
#endregion
public static void LinqShow()
{
List<Student> studentList = GetStudentList();
{//常规情况下过滤数据
var list = new List<Student>();
foreach (var item in studentList)
{
//Thread.Sleep(500);
Console.WriteLine("判断数据");
if (item.Age < 30)
{
list.Add(item);
}
}
}
#region Linq To Object(Enumerable)
{//采用Linq方法
//使用Student类型的扩展方法
var result = studentList.CgcWhere(s => s.Age < 30);//陈述式语法,CgcWhere扩展方法
//使用泛型扩展方法GenericCgcWhere
new List<int>() { 1, 2, 3, 4, 5, 6, 7, 8, 9 }.GenericCgcWhere(i => i < 5);
//使用迭代器的扩展方法
var result1 = studentList.YieldCgcWhere(s =>
{
Console.WriteLine("判断数据");
//Thread.Sleep(500);
return s.Age < 30;
});//在这里并不会执行扩展方法
foreach(var item in result1)
{
Console.WriteLine(item);
}//只有在使用时才去执行扩展方法
}
{//Where:完成对数据集合的过滤,通过委托封装完成通用代码,泛型+迭代器去提供特性
var linq = studentList.Where(s =>
{
Console.WriteLine("判断数据");
//Thread.Sleep(500);
return s.Age < 30;
});
}
{
//Select:完成对数据集合的转换,通过委托封装完成通用代码,泛型+迭代器去提供特性
var linq = studentList.
Where(s =>
{
Console.WriteLine("判断数据");
//Thread.Sleep(500);
return s.Age < 30;
})
.Select<Student, int>(s => s.Name.Length);
}
{
//Select:完成对数据集合的转换,通过委托封装完成通用代码,泛型+迭代器去提供特性
var linq = studentList
.Where(s =>
{
Console.WriteLine("判断数据");
//Thread.Sleep(500);
return s.Age < 30;
})
.Select(s => new
{
Id=s.Id,
Name=s.Name,
Length=s.Name.Length
});
foreach(var item in linq)
{
//item.Id;
//item.Name;
}
}
{
//Min/Max/OrderBy/GroupBy等:完成对数据集合的转换,通过委托封装完成通用代码,泛型+迭代器(有些没有)去提供特性
{
Console.WriteLine("********Ling To Object********");
var list = studentList.Where<Student>(s => s.Age < 30);
foreach (var item in list)
Console.WriteLine("Name={0} Age={1}", item.Name, item.Age);
}
{
Console.WriteLine("与上面的效果一致");
var list = from s in studentList
where s.Age < 30
select s;
foreach (var item in list)
Console.WriteLine("Name={0} Age={1}", item.Name, item.Age);
}
{
Console.WriteLine("投影,转换成一个新的对象");
var list = studentList.Where(s => s.Age < 30).Select(s => new
{
IdName = s.Id + s.Name,
ClassName = s.ClassId == 2 ? "高级班" : "其他班"
});
foreach (var item in list)
Console.WriteLine("IdName={0} ClassName={1}", item.IdName, item.ClassName);
}
{
Console.WriteLine("与上一个相同");
var list = from s in studentList
where s.Age < 30
select new
{
IdName = s.Id + s.Name,
ClassName = s.ClassId == 2 ? "高级班" : "其他班"
};
foreach (var item in list)
Console.WriteLine("IdName={0} ClassName={1}", item.IdName, item.ClassName);
}
{
Console.WriteLine("条件筛选");
var list = studentList.Where(s => s.Age < 80).Select(s => new
{
Id = s.Id,
ClassId = s.ClassId,
IdName = s.Id + s.Name,
ClassName = s.ClassId == 2 ? "高级班" : "其他班"
}).OrderBy(s => s.Id)//递增排序
.OrderByDescending(s => s.ClassId)//递减排序
.Skip(2)//跳过几条,之前需要先排序
.Take(3);//获取几条,之前需要先排序
foreach (var item in list)
Console.WriteLine("IdName={0} ClassName={1}", item.IdName, item.ClassName);
}
{
Console.WriteLine("GroupBy");
var list = from s in studentList
where s.Age < 80
group s by s.ClassId into sg
select new
{
key = sg.Key,
maxAge = sg.Max(t => t.Age)
};
foreach (var item in list)
Console.WriteLine($"key={item.key} ClassName={item.maxAge}");
}
List<Class> classList = new List<Class>()
{
new Class()
{
Id=1,
ClassName="初级班"
},
new Class()
{
Id=2,
ClassName="高级班"
},
new Class()
{
Id=3,
ClassName="网络班"
},
};
{
Console.WriteLine("关联表:关键字形式");
var list = from s in studentList
join c in classList on s.ClassId equals c.Id
select new
{
Name = s.Name,
ClassName = c.ClassName
};
foreach (var item in list)
Console.WriteLine($"Name={item.Name},ClassName={item.ClassName}");
}
{
Console.WriteLine("关联表:扩展方法形式");
var list = studentList.Join(classList, s => s.ClassId, c => c.Id, (s, c) => new
{
Name = s.Name,
ClassName = c.ClassName
});
foreach (var item in list)
Console.WriteLine($"Name={item.Name} ClassName={item.ClassName}");
}
{
Console.WriteLine("左连接:关键字形式");
var list = from s in studentList
join c in classList on s.ClassId equals c.Id
into scList
from sc in scList.DefaultIfEmpty()
select new
{
Name = s.Name,
ClassName = sc == null ? "无班级" : sc.ClassName//c变sc,为空则用
};
foreach (var item in list)
Console.WriteLine($"Name={item.Name} ClassName={item.ClassName}");
}
//右连接则将s和c的位置交换一下即可,没有右连接的写法形式
{
Console.WriteLine("左连接:扩展方法形式");
var list = studentList.Join(classList, s => s.ClassId, c => c.Id, (s, c) => new
{
Name = s.Name,
ClassName = c.ClassName
});
foreach (var item in list)
Console.WriteLine($"Name={item.Name} ClassName={item.ClassName}");
}
//以上的关键字编译后都变成了扩展方法形式,相当于关键字其实是语法糖,由编译器提供的
int? value = null;//可空类型:指向Nullable<int>,与int相比是另一种类型
int value1 = default(int);//默认值为0
int? value2 = default(int?);//默认值为null
int? value3 = 3;
int? value4 = new int?(3);
int? value5 = new Nullable<int>(3);
int value6 = (int)value4;//int?转换为int
int sum = value1 + (int)value3;
int? sum1 = value1 + value3;
value1 = 5;
value3 = null;
int? sum2 = value1 + value3;//任何int值与值为null的int?运算结果为null
}
}
#endregion
//Lambda声明属性
public int id => 3;
public void ShowLambda() => Console.WriteLine("LambdaFunc");
//Linq To Sql(Queryable):SQL+ADO.NET
//Where:完成对数据库的过滤,封装通用代码。
//Linq To XML
//Linq To Excel/Nosql
//Linq To Everything
}
#endregion
/// <summary>
/// 学生类
/// </summary>
public class Student
{
public int Id { get; set; }
public int ClassId { get; set; }
public string Name { get; set; }
public int Age { get; set; }
public void Study()
{
Console.WriteLine("自学C#高级课程");
}
public void StudyHard()
{
Console.WriteLine("努力自学C#高级课程");
}
}
/// <summary>
/// 班级类
/// </summary>
public class Class
{
public int Id;
public string ClassName;
}
/// <summary>
/// 扩展方法:静态类里面的静态方法,第一个参数类型前面加上this
/// 用途:不修改类,增加方法,用起来方便一些。
/// 缺陷:如果类内已经有了扩展方法相同的方法,优先调用类内的实例方法(有隐患)。
/// 指定类型扩展,不要扩展object。
/// </summary>
public static class ExtendMethod
{
public static void Sing(this Student student)
{
Console.WriteLine("Sing a song");
}
/// <summary>
/// null默认是defaultValue,默认是0
/// </summary>
/// <param name="iValue"></param>
/// <param name="defaultValue"></param>
/// <returns></returns>
public static int ToInt(this int? iValue, int defaultValue = 0)
{
return iValue ?? defaultValue;//如果iValue不为空,返回iValue,否则返回-1。
}
/// <summary>
/// 扩展基类型,导致任何子类都有这个方法,而且可能覆盖方法名相同的方法,非常不推荐扩展object类型
/// </summary>
/// <param name="oValue"></param>
/// <returns></returns>
public static int Length(this object oValue)
{
return oValue == null ? 0 : oValue.ToString().Length;
}
/// <summary>
/// 泛型扩展方法要加约束,否则和扩展object类型效果一样
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="t"></param>
public static void ExtendShow<T>(this T t) where T : Student //泛型约束
{
Console.WriteLine("I am ExtendShow");
}
/// <summary>
/// 扩展方法,只针对Student
/// </summary>
/// <param name="source"></param>
/// <param name="func"></param>
/// <returns></returns>
public static List<Student> CgcWhere(this List<Student> source, Func<Student, bool> func)
{
var list = new List<Student>();
foreach (var item in source)
{
if (func.Invoke(item))
{
list.Add(item);
}
}
return list;
}
/// <summary>
/// 泛型扩展方法,可以针对任何类型
/// </summary>
/// <param name="source"></param>
/// <param name="func"></param>
/// <returns></returns>
public static List<T> GenericCgcWhere<T>(this List<T> source, Func<T, bool> func)
{
var list = new List<T>();
foreach (var item in source)
{
if (func.Invoke(item))
{
list.Add(item);
}
}
return list;
}
/// <summary>
/// 加上迭代器的扩展方法,按需加载:标准的Linq
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="source"></param>
/// <param name="func"></param>
/// <returns></returns>
public static IEnumerable<T> YieldCgcWhere<T>(this IEnumerable<T> source, Func<T, bool> func)
{
if(source==null)
{
throw new Exception("source is null");
}
if(func==null)
{
throw new Exception("func is null");
}
foreach (var item in source)
{
if (func.Invoke(item))
{
yield return item;
}
}
}
}
#endregion
}
上一篇: Linq初学用法(3) 从dataTable 取出一列值
下一篇: 单利模式