C#.委托赋值表达式,匿名方法与Lambda
委托
委托是一种特殊的引用类型, 所以使用委托类似于使用一个类, 需要先声明, 然后再调用. 与一般类的声明又有所不同, 不使用class
和new
关键字, 而是使用专门的delegate
. 是否与 py 和 js 一样可以直接将方法赋给一个变量然后调用呢? 不可以, 编译器会报错, 尚不知如何声明一个方法组对象变量. 在思考委托时, 不能仅仅把委托对象当作一个方法的别名, 他就是一个委托类的实例, 就是委托对象, 以笔者的知识储备来看, 它是一个全新的数据结构, 有他自己的特性. 使用委托一般是三个步骤: 声明委托类, 创建委托对象, 绑定方法.
delegate void CalcuAndPrint(int a, int b);
// 声明一个委托类, 可以看见括号前面是绿色的, 是类名的高亮
class Program
{
static void SumAndPrint(int a, int b)
{
Console.WriteLine(a + b);
}
static void SubAndPrint(int a, int b)
{
Console.WriteLine(a - b);
}
static CalcuAndPrint GiveMeTwoFunc()
{
CalcuAndPrint func = SumAndPrint;
return func += SubAndPrint;
}
static void Main()
{
CalcuAndPrint func;
// 委托类不是静态类, 使用需要实例化
func = SumAndPrint;
// 为委托对象赋值, 值是一个方法
func(1,1); // 如同函数一样调用委托对象
// void func2 = SumAndPrint;
// 错误 CS0029 无法将类型“方法组”隐式转换为“void”
// 错误 CS1547 关键字 "void" 不能在此上下文中使用
func += SubAndPrint;
// func += (CalcuAndPrint)SubAndPrint; // 显式转换, 可行.
// 本质是"方法组"向"委托"的隐式转换
// var func0 = SumAndPrint;
// 错误 CS8400 功能“推断的委托类型”在 C# 8.0 中不可用。请使用语言版本 10.0 或更高版本。
// func += new CalcuAndPrint(Program.SubAndPrint); // 完整写法
func(9,6);
GiveMeTwoFunc()(6,9);
// 委托对象直接通过方法的返回值返回.
// 可以直接调用这个委托类, 不用重新声明变量赋值再调用委托对象
}
}
委托赋值表达式
简写形式可以用var
关键字简化吗? 虽然说方法作为参数传递需要先封装成委托, 但可以直接传递吗? 不可使用var
, .net core 3.1 使用的 8.0 版本的 C#, 功能“推断的委托类型”在 C# 8.0 中不可用. 请使用语言版本 10.0 或更高版本. 第二个问题如之前的问题一样, 方法的类型名为方法组, 参数传递时需要声明类型, 方法组目前尚不可知, 不能绕过委托直接传递. 所谓的委托赋值表达式的简写形式, 其实是方法组类型对象向委托类型对象类型的隐式转换.
匿名方法与Lambda
public class Stu
{
static private int _id = 1120000;
private string name;
public string Name {get { return name; } }
private int id;
private int age;
public int Age { get { return age; } }
private int avgScore;
public int Score {
get { return avgScore; }
set { avgScore = value; }
}
public Stu(string name, int age, int score)
{
id = _id;
_id++;
this.age = age;
avgScore = score;
this.name = name;
}
public delegate Stu StuCompareMethod(Stu stu1, Stu stu2);
public override string ToString()
{
return $"{id}:{name} {age}, {avgScore}";
}
public static void SortAndPrint(Stu[] Stus, StuCompareMethod method)
{
Stu temp;
for (int i = 0; i < Stus.Length; i++)
{
for (int j = Stus.Length - 1 ; j > i; j--)
{
if (method(Stus[j],Stus[j-1]) != Stus[j])
{
temp = Stus[j];
Stus[j] = Stus[j-1];
Stus[j-1] = temp;
}
}
}
foreach (Stu stu in Stus)
{
Console.WriteLine(stu);
}
}
}
internal class Program
{
static void Main(string[] args)
{
Stu stu0 = new Stu("LongX", 7, 90);
Stu stu1 = new Stu("DaMo",11,95);
Stu stu4 = new Stu("U", 60, 100);
Stu stu2 = new Stu("Emotion", 15, 85);
Stu stu3 = new Stu("Jayden", 19, 87);
Stu[] Stus = {stu0,stu1,stu4,stu2,stu3};
Stu.StuCompareMethod SortByAgeDesc = delegate (Stu stu1, Stu stu2)
{
if (stu1.Age < stu2.Age)
{
return stu1;
}
else
{
return stu2;
}
}; // 按Age降序, 匿名方法描述
// 匿名方法需要先声明委托对象变量. 这里的匿名是函数没有名字
// 赋值号前面的变量名不是函数的, 是委托对象的变量名.
// 匿名方法描述直接在赋值号后使用 delegate 关键字
// 紧随其后定义参数和方法体, 直接完成了委托绑定
Stu.SortAndPrint(Stus, SortByAgeDesc);
Console.WriteLine("");
// 按Score升序, Lambda 表达式描述
// (参数类型 参数名) => { return 返回值;}
// 最简方式: (参数名) => 返回值
// 使用 Lambda 表达式不需要额外绑定委托
// 在参数传递时, Lambda 表达式将自动从方法组隐式转化为委托
Stu.SortAndPrint(Stus, (stu1, stu2) => (stu1.Score > stu2.Score) ? stu1 : stu2);
}
}
委托加减运算
连续输出是什么意思? 顺序又是怎样? 按照目前的例子来看, 是按照绑定是的顺序进行的连续输出.