C#进阶知识
大家好,我是行不更名,坐不改姓的宋晓刚,下面将带领大家从基础小白到高阶的C#的学习,跟上我的步伐进入C#的世界。
微信:15319589104
QQ: 2981345658
泛型
C#中的泛型是一种确定类型的方式,它使开发人员可以编写可以重用且类型安全的代码。泛型可用于类、接口、方法和委托中。
泛型的声明主要只有四种,泛型方法(常用),泛型类,泛型接口,泛型委托
泛型类
泛型类是包含一个或多个类型参数的类,这些类型参数可以在类中任何需要实际类型的位置使用。
public class MyDxx<T>
{
public T Dxx { get; set; }
public void Dxx1(T Value)
{
}
}
如上,我们定义了一个名字为MyDxx的泛型类,它有一个类型参数T,该类提供了一个公共属性Dxx和一个公共方法Dxx1,这个俩个成员都使用泛型类型参数T,这个类型参数T的实际类型在类的实例化确定。
泛型方法
泛型方法是一种可以包含一个或多个类型参数的方法,这些类型参数可以在方法体中使用。泛型方法的语法如下:
public void Dxx<T>(T Value)
{
}
在上述代码中,我们定义了一个名为 Dxx
的泛型方法,它有一个类型参数 T
。该方法接受一个名为 value
的参数,这个参数是一个类型为 T
的对象。
如何调用和使用泛型
在C#中,我们可以使用泛型类型来实例化具有特定类型参数的类、结构和接口。例如,以下是我们如何实例化前面提到的 MyDxx
类型:
泛型类:
public class MyDxx<T>
{
public T Dxx { get; set; }
public void Dxx1(T Value)
{
Console.WriteLine("参数为:"+Value);
}
}
使用方法:
static void Main(string[] args)
{
//定义一个整形
MyDxx<int> IntDx = new MyDxx<int>();
IntDx.Dxx1(2);
//定义一个字符串
MyDxx<string> StringDxx = new MyDxx<string>();
StringDxx.Dxx1("张三");
}
我们创建了两个 MyDxx
类型的实例,一个使用 int
类型的实际类型参数,另一个使用 string
类型的实际类型参数。
泛型约束语法
通常,在声明泛型类型或方法时,可以使用where
关键字来定义泛型类型参数的约束。泛型约束定义前缀为where
,后跟泛型类型参数名称和约束列表。(可以叠加使用)
class/struct约束
可以使用class
或struct
约束类型,将泛型类型参数限制为引用类型或值类型之一。以下是一个将泛型类型参数T
限制为引用类型的示例。
public class Example<T> where T : class
{
// Class body
}
以下是一个将泛型类型参数T
限制为值类型的示例。
public class Example<T> where T : struct
{
// Class body
}
new()约束
可以使用new()
约束将泛型类型参数限制为拥有公共无参构造函数的类型。以下是一个将泛型类型参数T
约束为拥有默认构造函数的类型的示例。
public class Example<T> where T : new()
{
// Class body
}
接口约束
可以使用接口约束来指定泛型类型参数必须实现一个或多个接口。以下是一个限制泛型类型参数T
实现IComparable
接口的示例。
public class Example<T> where T : IComparable
{
// Class body
}
反射
反射提供了以下几个优点:
- 动态地操作类型和成员。
- 在运行时查看类型和成员的元数据信息。
- 允许实现泛型类型和方法的通用算法。
- 为不适用常规的编程模式的代码提供了可靠的替代方案。
反射的语法
在 C# 中,我们可以使用 **System.Reflection **命名空间中的类型来访问特定程序集、类型和成员的元数据信息。以下是一些常用的反射类:
- Assembly:表示程序集,包括模块、类型、成员和清单等信息。
- Type:表示类型,包括其名称、命名空间、基类、实现接口、字段、方法、属性和事件等信息。
- MethodInfo:表示方法,包括其名称、返回类型、参数列表、方法体等信息。
- PropertyInfo:表示属性,包括其名称、类型、访问器等信息。
- FieldInfo:表示字段,包括其名称、类型、访问级别等信息。
获取程序集(Assembly)
获取程序集可以使用以下方法:
// 通过程序集文件路径获取程序集
Assembly assembly = Assembly.LoadFrom("assembly_path");
// 获取当前执行的程序集
Assembly assembly = Assembly.GetExecutingAssembly();
// 获取指定类型所在的程序集
Assembly assembly = typeof(MyClass).Assembly;
// 获取所有已加载的程序集
Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
获取类型(Type)
获取类型可以使用以下方法:
// 通过类型名称获取类型
Type type = Type.GetType("Namespace.MyClass");
// 通过程序集和类型名称获取类型
Assembly assembly = Assembly.LoadFrom("assembly_path");
Type type = assembly.GetType("Namespace.MyClass");
// 获取对象的类型
MyClass obj = new MyClass();
Type type = obj.GetType();
获取成员(Member)
获取成员可以使用以下方法:
// 获取类型的所有字段(包括公共、私有、静态、非静态)
FieldInfo[] fields = type.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance);
// 获取类型的所有方法(包括公共、私有、静态、非静态)
MethodInfo[] methods = type.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance);
// 获取类型的所有属性(包括公共、私有、静态、非静态)
PropertyInfo[] properties = type.GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance);
// 获取类型的所有事件(包括公共、私有、静态、非静态)
EventInfo[] events = type.GetEvents(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance);
// 获取类型的所有自定义特性
Attribute[] attributes = Attribute.GetCustomAttributes(type);
调用方法(Method)和属性(Property)
调用方法和属性可以使用以下方法:
// 创建对象
MyClass obj = Activator.CreateInstance<MyClass>();
// 调用静态方法
MethodInfo method = type.GetMethod("StaticMethod", BindingFlags.Public | BindingFlags.Static);
object result = method.Invoke(null, parameters);
// 调用非静态方法
MethodInfo method = type.GetMethod("InstanceMethod", BindingFlags.Public | BindingFlags.Instance);
object result = method.Invoke(obj, parameters);
// 获取和设置属性值
PropertyInfo property = type.GetProperty("MyProperty", BindingFlags.Public | BindingFlags.Instance);
object value = property.GetValue(obj);
property.SetValue(obj, value);
// 获取和设置字段值
FieldInfo field = type.GetField("MyField", BindingFlags.Public | BindingFlags.Instance);
object value = field.GetValue(obj);
field.SetValue(obj, value);
创建和获取构造函数(Constructor)
创建和获取构造函数可以使用以下方法:
// 获取无参构造函数
ConstructorInfo ctor = type.GetConstructor(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance, null, Type.EmptyTypes, null);
// 获取有参构造函数
ConstructorInfo ctor = type.GetConstructor(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance, null, new Type[] { typeof(int), typeof(string) }, null);
// 创建对象
MyClass obj = (MyClass)ctor.Invoke(new object[] { arg1, arg2 });
学习代码时的笔记:
using System.Reflection; //要使用反射必须使用的一个命名空间
namespace ConsoleApp5
{
public class UserInfo
{
public UserInfo()
{
Console.WriteLine("UserInfo对象被创建");
}
public UserInfo(int id,string name)
{
UserId = id;
UserName= name;
}
private int id;
public int UserId {get; set;}
public string UserName { get; set; }
public int Age { get; set; }
public void Show()
{
Console.WriteLine("Show UserInfo");
}
public void Show(string name)
{
Console.WriteLine("Show"+name);
}
public static void ShowInfo()
{
Console.WriteLine("ShowInfo UserInfo");
}
public int GetAge()
{
return Age;
}
}
internal class Program
{
static void Main(string[] args)
{
//创建对象
UserInfo user1 = new UserInfo(); //创建实例
//假设不直接创建
Type type = typeof(UserInfo); //获取类型的Type对象
UserInfo user2 = Activator.CreateInstance<UserInfo>(); //创建UserInfo实例
UserInfo user3 = (UserInfo)Activator.CreateInstance(type); //使用默认构造函数创建实例
//获取类成员
var properties = type.GetProperties(); //所有的公有属性
PropertyInfo prold = type.GetProperty("UserId"); //指定的公开属性
var fields = type.GetFields(); //字段
//获取私有的字段
var prifirlds = type.GetFields(BindingFlags.Instance | BindingFlags.NonPublic);
var pubMethods = type.GetMethods(); //获取所有公开方法
//方法的获取与调用
//匹配无参数的Show方法
object user4 = Activator.CreateInstance(type);
MethodInfo mShow = type.GetMethod("Show", new Type[] { });
mShow.Invoke(user4, null);
//匹配带参数的Show方法
MethodInfo mShow1 = type.GetMethod("Show",new Type[] {typeof(string)});
mShow1.Invoke(user4, new object[] { "点点" }); //赋值后调用方法
//静态方法的获取
MethodInfo staticShow = type.GetMethod("ShowInfo", new Type[] { });
staticShow.Invoke(null, null); //静态方法调用,第一个参数null
//获取构造函数以及用构造函数创建对象
var cons = type.GetConstructors(); //公共的构造函数
ConstructorInfo cons1 = type.GetConstructor(new Type[] { });
ConstructorInfo cons2 = type.GetConstructor(new Type[] { typeof(int), typeof(string) });
UserInfo user5 = (UserInfo)cons1.Invoke(null); //调用无参构造函数
object user6 = cons2.Invoke(new object[] { 12, "Mr.Sun" });
//加载程序集
//三种方式
//1.Load() 文件名不带后缀
Assembly ass = Assembly.Load("Models");
Type typeMenu = ass.GetType("Models.MenuInfo"); //类的完整性名称 命名空间+类名
}
}
}
委托
理论知识:
委托从字面上理解就是一种代理,类似房屋中介,由租房人委托中介为其租凭房屋。
委托在使用时遵循三步走的原则,即定义声明委托、实例化委托以及调用委托。
委托是 C# 语言中的一个特色,通常将委托分为命名方法委托、多播委托、匿名委托,其中命名方法委托是使用最多的一种委托。
C#命名方法委托
1.在 C#语言中命名方法委托是最常用的一种委托,其定义的语法形式如下。
修饰符 delegate 返回值类型 委托名 ( 参数列表 );
从上面的定义可以看出,委托的定义与方法的定义是相似的。例如定义一个不带参数的委托,代码如下。
public delegate void MyDxx(); //无参数的委托
2.定义好委托后就到了实例化委托的步骤,命名方法委托在实例化委托时必须带入方法的具体名称。
实例化委托的语法形式如下。
委托名 委托对象名 = new 委托名 (类名 . 方法名 ); //实例化委托
在委托中所写的方法名必须与委托定义时的返回值类型和参数列表相同
3.在实例化委托后既可调用委托,语法如下。
委托对象名 ( 参数列表 );
下面分别通过两个实例来演示在委托中应用静态方法和实例方法的形式:
1.创建委托,在委托中传入静态方法于控制台输出。
若使用静态方法,在向委托中传递方法名时只需要用“类名.方法名”的形式。
class Test //创建一个类,包含着一个静态方法
{
public static void SayHello()
{
Console.WriteLine("你好,委托调用成功");
}
}
internal class Program
{
public delegate void MyDxx(); //创建一个MyDxx的委托
static void Main(string[] args)
{ //实例化这个委托
MyDxx Duxingxia = new MyDxx(Test.SayHello); //传递参数时,只需要(类名.方法名)的形式
Duxingxia(); //调用委托
} //输出你好,委托调用成功
}
2.将上面的静态方法改为实例方法
class Test //创建一个类,包含着一个静态方法
{
public void SayHello()
{
Console.WriteLine("你好,委托调用成功");
}
}
internal class Program
{
public delegate void MyDxx(); //创建一个MyDxx的委托
static void Main(string[] args)
{ //实例化这个委托
MyDxx Duxingxia = new MyDxx(new Test().SayHello); //委托中实例来调用方法,使用(new类名().方法名)的形式
Duxingxia(); //调用委托
}
}
执行代码与上面的一致,不一致的是实例化调用方法的时候不一致。
由于在委托中使用的是实例方法,则需要通过类的实例来调用方法,即使用“new 类名 (). 方法名”的形式。
C#多播委托
定义:
在C#语言中多播委托是指在一个委托中注册多个方法,在注册方法时可以在委托中使用加号运算符或减号运算符来实现添加或撤销方法。
在现实生活中,多播委托的实例时随处可见的,例如某点餐的应用程序,既可以预定普通的餐饮也可以预定蛋糕、鲜花、水果等商品。
在这里委托相当于点餐平台,每一个类型的商品可以理解为在委托上注册的一个方法。
下面来模拟点餐平台预定不同类型的商品(实例中预定快餐,蛋糕,鲜花三类商品):
class Shop //创建商店的一个类,包含三个商品的方法
{
public static void BuyFood()
{
Console.WriteLine("购买快餐");
}
public static void BuyCake()
{
Console.WriteLine("购买蛋糕");
}
public static void BuyFlower()
{
Console.WriteLine("购买鲜花");
}
}
internal class Program
{ //定义委托
public delegate void ShopDelegate();
static void Main(string[] args)
{
//实例化委托(类名+方法名)
ShopDelegate shopDelegate = new ShopDelegate(Shop.BuyFood);
//向委托中注册方法
shopDelegate += Shop.BuyCake;
shopDelegate += Shop.BuyFlower;
shopDelegate();
//我们也可以撤掉委托注册的方法
shopDelegate -= Shop.BuyFood;
shopDelegate();
}
}
多播委托如上:
我们先定义了商店类中的三个商品方法,然后在主方法中,定义委托,进行委托实例,然后进行注册方法,同时也可以撤销委托。
向委托中注册方法:
委托名 += 类名.方法名
shopDelegate += Shop.BuyCake;
向委托中撤销方法:
委托名 -= 类名.方法名
shopDelegate -= Shop.BuyFood;
匿名委托
在 C# 语言中匿名委托是在委托中通过定义代码块来实现委托的作用,具体的语法形式如下。
//1. 定义委托
修饰符 delegate 返回值类型 委托名 ( 参数列表 );
//2. 定义匿名委托
委托名 委托对象 = delegate
{
//代码块
};
//3. 调用匿名委托
委托对象名 ( 参数列表 );
通过上面 3 个步骤即可完成匿名委托的定义和调用,需要注意的是,在定义匿名委托时代码块结束后要在 {} 后加上分号。
下面通过实例来演示匿名委托的应用。(使用匿名委托计算长方形的面积。)
internal class Program
{ //1.定义委托
public delegate void AreaDelegate(double length,double width);
static void Main(string[] args)
{
Console.WriteLine("请输入长方形的长:");
double lenth = double.Parse(Console.ReadLine());
Console.WriteLine("请输入长方形的宽:");
double width = double.Parse(Console.ReadLine());
//2.定义匿名委托
AreaDelegate areaDelegate = delegate
{
Console.WriteLine("长方形的面积为:" + lenth * width);
};
//3.调用匿名委托
areaDelegate(lenth, width);
}
}
从上面的执行效果可以看岀,在使用匿名委托时并没有定义方法,而是在实例化委托时直接实现了具体的操作。
由于匿名委托并不能很好地实现代码的重用,匿名委托通常适用于实现一些仅需要使用一次委托中代码的情况,并且代码比较少。
Lambda
Lambda是一种匿名函数,可以在C#中方便地实现函数式编程。
1.未使用Lambda之前的匿名函数(匿名委托)
internal class Program
{ //定义委托
public delegate void Dxx(int x);
static void Main(string[] args)
{
int y = 2;
//定义匿名委托
Dxx Dxx1 = delegate (int x)
{
x += 1;
Console.WriteLine("x的值为多少"+x);
Console.WriteLine("y的值为多少"+y);
};
Dxx1(y); //调用匿名委托
}
}
2.使用Lambda后的
internal class Program
{ //定义委托
public delegate void Dxx(int x);
static void Main(string[] args)
{
int y = 2;
//定义匿名委托
Dxx Dxx1 = delegate (int x)
{
x += 1;
Console.WriteLine("x的值为多少"+x);
Console.WriteLine("y的值为多少"+y);
};
Dxx1(y); //调用匿名委托
//1.去掉了delegate,参数列表与主体之间, =>
Dxx Dxx2 = (int x) =>
{
x += 1;
Console.WriteLine("x的值为多少" + x);
Console.WriteLine("y的值为多少" + y);
};
Dxx2(y);
//2.去掉了参数类型,如果{}中主体只有一句话,{}可以不写
Dxx Dxx3 = x =>
{
x += 1;
Console.WriteLine("x的值为多少" + x);
Console.WriteLine("y的值为多少" + y);
};
Dxx3(y);
}
}
如上我们利用Lambda去掉了关键字delegate,同时还去掉了值类型,这样使得我们代码更加简单明了。
Action
概念:
Action
在 C# 中是一个委托类型,可以表示一个不带参数并且不返回值的方法,也可以表示带有多个参数但是不返回值的方法。
没有返回值委托 可以不带参数,也可以带参数,最多可以带16个参数。
简单的Action委托:
Action act1 = () => { }; //最简单的委托
Action act2 = () => Console.WriteLine("Hello World!");
Action act3 = () =>
{
string a = "DUxinghxas";
};
带参数的:
Action<int> act4 = a => { int b = a + 3; }; //这里不能省略{}
//俩个参数
Action<int, string> act5 = (c, d) =>
{
Console.WriteLine("c" + c + "; d" + d);
};
Func
可以不带参数,可以带参数,最多16个参数,只可以返回一个值。
简单的定义一个Func不带参数,返回一个string类型的值
//不带参数,返回一个string类型的值
Func<string> func1 = () => "sss";
定义带俩个参数string int, 返回值类型时string。
//带俩个参数string int,返回值类型string
Func<string, int, string> func3 = (q1, q2) =>
{
string q3 = q1 + q2;
return q3;
};
事件
可以理解为是一个用户操作,如按键,点击,鼠标移动等等,或者是一些提示信息。应用程序需要在事件发生时响应事件,例如,点击按钮,显示消息框。
事件在类中声明而生成的,且通过使用同一个类或其他类中的委托与事件处理程序关联,事件是在法布雷中调用,外部不能调用,
如下,事件使用发布 订阅的模型,event为事件的关键字。
- 1.0 包含事件的类用于发布事件,称为发布器类。
- 2.0 接收该事件的类被称为订阅器类。
事件的声明
1.首先,我们声明事件之前,需要定义一个委托类型,该委托类型用于封装事件处理方法的签名。
//定义委托
public delegate void Dxingxia(object send,string message);
//定义事件
public event Dxingxia MyDxx;
如上,使用evnet关键字,将委托类型和事件关联起来。
上课的代码与注释:
class People
{
//委托
public delegate void Dxingxia(object send,EventArgs e);
//事件
public event Dxingxia MyDxx;
//事件不能在外部调用,只能在内部发布,这里的发布为People
public int Stuld { get; set; }
public string Name { get; set; }
public void StartCourse()
{
//如果MyDxx不为空,就点击事件
MyDxx?.Invoke(this,new EventArgs());
}
}
如上,是一个发布器,首先我们定义了一个People的类,声明委托与事件,用evnet关键字关联起来,
然后定义了一个方法,如果不为空,就点击事件。
事件的处理方法
事件的处理方法,也就是订阅事件的方法。
class People
{
//委托
public delegate void Dxingxia(object send,EventArgs e);
//事件
public event Dxingxia MyDxx;
//事件不能在外部调用,只能在内部发布,这里的发布为People
public int Stuld { get; set; }
public string Name { get; set; }
public void StartCourse()
{
//如果MyDxx不为空,就点击事件
MyDxx?.Invoke(this,new EventArgs());
}
}
internal class Program
{
static void Main(string[] args) //主方法中声明ding'y
{
//订阅器
People people = new People()
{
Stuld = 0,
Name = "独行侠",
};
people.MyDxx += People_MyDxx; //+=后面直接俩次Tap,就出来后面的参数了
people.StartCourse();
}
private static void People_MyDxx(object send, EventArgs e)
{
Console.WriteLine("正在学习中");
}
}
特性
特性是用于运行传递程序中各种元素(比如类,方法,结构,枚举,组件等)的行为信息的声明性标签,一个声明性标签师通过放置在它所应用的元素前面的方括号([ ])来描述的。
特性用于添加元数据,如编译器指令和注释,描述,方法,类等其他信息。
.Net框架提供了俩种类型的特性 : 预定义特性和自定义特性。
预定义特性
预定义的特性(需要掌握一种):
[AttributeUsage]
:用于指定一个特性可以用于哪些元素。
语法:
[Attribute(arg1, arg2, ...)]
其中的 arg1
、arg2
等是特性的参数,多个参数用逗号分隔。
特性参数可以是字符串常量、枚举常量、常量表达式、typeof 运算符获得的类型对象、数组等,也可以是具有相应类型的限定条件的对象。
自定义特性
特性(Attribute)是一种可以在编译时将元数据附加到程序的声明中的方法。特性通常用于描述程序中的类型、变量、属性、方法等各种声明,以便为编译器、调试器和其他代码分析工具提供额外的信息。C#中也提供了一些常用的特性,例如[Serializable]、[Obsolete]等,这些特性可以用于标记类、结构体、方法等,以达到特定的目的。
如何创建一个自定义特性:
// 定义一个特性类
[AttributeUsage(AttributeTargets.Class)]
public class MyAttribute : Attribute
{
// 定义一个成员变量
private string _name;
// 定义一个构造函数
public MyAttribute(string name)
{
_name = name;
}
// 定义一个属性
public string Name
{
get { return _name; }
}
}
// 使用特性
[MyAttribute("MyClass")]
public class MyClass
{
// 类的成员
}
在上面的代码中,我们定义了一个特性类"MyAttribute",它派生自"Attribute"类,
并具有一个成员变量"_name"和一个构造函数,用于指定特性的名称。
然后,我们在"MyClass"类上应用了"MyAttribute"特性,以指示"MyClass"类拥有"MyAttribute"特性。
在编写程序时,您可以通过使用"typeof"操作符和"GetCustomAttributes"方法获取自定义特性:
// 获取特性
Type type = typeof(MyClass);
object[] attrs = type.GetCustomAttributes(typeof(MyAttribute), false);
// 打印特性信息
foreach (MyAttribute attr in attrs)
{
Console.WriteLine("Name: " + attr.Name);
}
在上面的代码中,我们使用"typeof"操作符和"GetCustomAttributes"方法获取了"MyClass"类中的所有"MyAttribute"特性,并在控制台上打印了它们的名称。
Linq
在C#中,Linq(Language-Integrated Query)是一种查询语言,可以在.net中查询语法。
Linq使用实例
//要查询的数据源
int[] numbers = {1,2,3,4,5,6,7,8,9 };
//查询表达式 -> 查询numbers中的所有数据
var duxingxia = from n in numbers
select n;
//打印输出结果
foreach (var n in duxingxia)
{
Console.WriteLine(n);
}
//查询语句加了where条件判断
var duxingxia1 = from a in numbers
where a % 2 == 0
select a;
foreach (var a in duxingxia1)
{
Console.WriteLine(a);
}
上面的代码中定义了一个数组的数据源,案例1中查询了数据源中的所有数据打印输出,案例2中查询了数据源中的偶数值打印输出。
- 定义了一个整型数组numbers。
- 使用"from"关键字和"where"子句创建了一个查询表达式,查询偶数的值。
- 执行了查询,并使用"foreach"循环打印了结果
同时,Linq还支持对查询结果进行多种操作,如分组,排序,投影。
分组(Group By)
分组(Group By)是Linq中一种将所有满足特定条件的元素根据共同的键值进行归类的操作。可以将分组操作看作将一组数据根据某个列(或属性)拆分成不同的数据段,每个数据段代表了某个列中同样的键值的一组元素。
在Linq中,分组操作可以通过使用group by
关键字来完成,通常的语法格式如下:
var result = from item in collection
group item by item.Key into g
select new
{
Key = g.Key,
Values = g.ToList(),
};
其中,collection
是要查询的集合,item.Key
代表用于分组的键值,g
是一个IGrouping<TKey, TElement>
类型对象,
表示一个键与其值的序列。
代码中的new
表达式则将结果封装为一个新的匿名类型,Key
表示分组键,Values
表示分组中的元素集合。
下面我们来定义一个类和属性,在类中定以数据源
internal class Person
{
public string Name { get; set; }
public int Age { get; set; }
}
static void Main(string[] args)
{
var persons = new List<Person>
{
new Person{Name = "Tom" ,Age = 20},
new Person { Name = "Jerry", Age = 25 },
new Person { Name = "Mike", Age = 20 },
new Person { Name = "John", Age = 30 },
new Person { Name = "Mary", Age = 25 }
};
}
使用Linq进行分组操作,并将结果打印出来。
static void Main(string[] args)
{
var duxingxia = from a in persons
group a by a.Age into g //进行年龄相等的进行分类
select new
{
Age = g.Key,
Persons = g.ToList()
};
//打印结果
foreach (var group in duxingxia)
{
Console.WriteLine("年龄为:"+group.Age);
foreach (var p in group.Persons)
{
Console.WriteLine("姓名:"+p.Name);
}
}
}
输出结果为:
年龄为:20
姓名:Tom
姓名:Mike
年龄为:25
姓名:Jerry
姓名:Mary
年龄为:30
姓名:John
上述代码将使用new
关键字将多个分组条件组合成了一个新的匿名类型。所以,可以对这些基于不同属性的分组进行组合和排序。
排序(orderBy)
Linq中的排序可以通过OrderBy
方法来完成,这个方法可以根据指定的条件对集合中的元素进行排序,通常的语法格式如下:
var result = from item in collection
orderby item.Field ascending/descending
select item;
其中,collection
是要查询的集合,item.Field
表示按照哪个字段进行排序,ascending
或descending
指定升序或降序排列方式。select
关键字后面可以跟上筛选或投映条件,如不需要,可省略。
- 升序: ascending 小到大
- 降序: descending 大到小
案例如下:
首先我们创建数据源,定义一个类,数据成员,在主方法中实例化这个类,创建个列表
internal class Student
{
public string Name { get; set; }
public int Age { get; set; }
}
static void Main(string[] args)
{
var student = new List<Student>
{
new Student { Name = "Tom", Age = 20 },
new Student { Name = "Jerry", Age = 25 },
new Student { Name = "Mike", Age = 18 },
new Student { Name = "John", Age = 30 },
new Student { Name = "Mary", Age = 22 }
};
}
创建好后,我们进行查询:
var students = from s in student
orderby s.Age descending //升序: ascending 小到大
select s; //降序: descending 大到小
foreach (var item in students)
{
Console.WriteLine(item.Age);
}
上述代码将按照Age
字段进行升序排列,使用select
选择这个排序之后的结果。如果需要以降序排列,则只需要将ascending
替换为descending
。