1、委托(Delegate)
这块基本来自C# 委托(Delegate) | 菜鸟教程
参考https://www.cnblogs.com/digital-college/p/17282032.html
委托(Delegate) 是存有对某个方法的引用的一种引用类型变量。引用可在运行时被改变。个人认为委托的主要意义就是能让调用的方法变量化,在其他方法里传递,类似于函数指针
public delegate void printString(string s);
...//上面的委托可被用于引用任何一个带有一个单一的 string 参数的方法,并返回一个 int 类型变量。
printString ps1 = new printString(WriteToScreen);
printString ps2 = new printString(WriteToFile);
委托声明决定了可由该委托引用的方法。委托可指向一个与其具有相同标签(即参数类型和返回类型一样)的方法。
一旦声明了委托类型,委托对象必须使用 new 关键字来创建,且与一个特定的方法有关。当创建委托时,传递到 new 语句的参数就像方法调用一样书写,但是不带有参数。
委托对象可使用 "+" 运算符进行合并。一个合并委托调用它所合并的两个委托。只有相同类型的委托可被合并。"-" 运算符可用于从合并的委托中移除组件委托。
使用委托的这个有用的特点,您可以创建一个委托被调用时要调用的方法的调用列表。这被称为委托的 多播(multicasting),也叫组播。
//定义一个委托
public delegate void MyDelegate1(int x);
public static void Method1(int a)
{
Console.WriteLine($"a={a}");
}
public static void Method2(int b)
{
Console.WriteLine($"b={b}");
}
static void Main(string[] args)
{
MyDelegate1 md = new MyDelegate1(Method1);
md += Method2;
md(35);
Console.ReadLine();
}
但是委托有一个弊端,它可以使用“=”将所有已经订阅的取消,只保留=后的这一个订阅。由此引出了event类型
2、事件(event)
大部分来自https://www.cnblogs.com/digital-college/p/17282032.html
事件event是一种特殊的委托实例,在定义类外它只能+=,-=,不能直接用=及其他的函数。事件常用来实现发布-订阅模式。
//定义一个委托
public delegate void MyDelegate1(int x);
//定义一个事件
public event MyDelegate1 emd;
经过长久的经验积累后,人们发现,绝大多数事件的委托的定义,是用public delegate void XXX(object sender, EventArgs e);这样一个委托原型进行定义的(括号里是参数),是一件重复性的工作,于是,EventHandler应运而生。它的出现就是为了避免这种重复性工作,并建议尽量使用该类型作为事件的原型。使用EventHandler时可以不用定义委托 。
public class Demo
{
public event EventHandler emd;
public void RaiseEvent()
{
emd?.Invoke(this, EventArgs.Empty);//只能在定义类调用
}
}
static void Main(string[] args)
{
var instance = new Demo();
instance.emd += (sender, arg) =>
{
Console.WriteLine("执行事件1!");
};//匿名函数
instance.emd += (sender, arg) =>
{
Console.WriteLine("执行事件2!");
};
instance.RaiseEvent();
Console.ReadLine();
}
注意里面的sender、arg是参数名,不是参数类型,参数类型事件里已经定义好了。同时,我们也可以看出:事件是按照+=的订阅先后顺序执行的。
除此以外还可以继承EventArgs类进行一些变形
public class ScoreEventArgs : EventArgs
{
public int Score { get; }
public ScoreEventArgs(int score) { Score = score; }// 只读属性的值在对象初始化期间(即在构造函数中)是可以被设置的。
}
public class Game
{
public event EventHandler<ScoreEventArgs> OnScoreChanged;
public void ChangeScore(int newScore)
{
OnScoreChanged?.Invoke(this, new ScoreEventArgs(newScore));
}
}
3、Func与Action
大部分来自https://www.cnblogs.com/digital-college/p/17282032.html
在委托delegate出现了很久以后,微软的.NET设计者们终于领悟到,其实所有的委托定义都可以归纳并简化成只用Func与Action这两个语法来表示。它们都是两种预定义的委托类型。其中,Func代表有返回值的委托,Action代表无返回值的委托。有了它们两,我们以后就不再需要用关键字delegate来定义委托了。这里也再次说明委托的意义是将方法变量化
同时,若再用lambda表达式取代被委托指向的具体方法,则整个委托的“定义+赋值”两步将大大简化(lambda表达式本来也是方法定义的一种简化形式)。
1)使用委托
// 定义一个接受两个int参数并返回int的委托类型
public delegate int MyDelegate(int x, int y);
// 使用委托
MyDelegate add = (a, b) => a + b;
int result = add(2, 3); // result = 5
2)使用Func
// 定义一个接受两个int参数并返回int的Func委托
Func<int, int, int> add = (a, b) => a + b;
int result = add(2, 3); // result = 5
这个例子没有体现出委托的可变性,来看下一个
//定义一个方法再把方法赋给Func委托
public static int Test(int a,int b)
{
return a+b;
}
Func<int, int, int> md=Test;
int result = md(2,3);
3)使用Action(Action更像是一种泛型事件)
public class Game
{
public Action<int> OnScoreChanged;
public void ChangeScore(int newScore)
{
OnScoreChanged?.Invoke(newScore);
}
}
匿名函数待补充