C委托和事件
C#委托和事件
一、委托
委托概念
有的开发者称委托为代理,事件委托= =事件代理。
委托是用户自定义类型,这一点和类,接口等一样的。委托是引用类型。
现实中:张三委托李四去做一件事。站在张三的角度,张三委托了李四,站在李四的角度,李四是张三的代理。
C#语言中的委托比较抽象:【 委托指向一系列具有相同签名和返回类型的方法的地址 】。
当一个方法,它的返回值和参数列表(参数个数,顺序,类型)和某个委托匹配,此委托就可以去代理此方法。
委托可以指向方法的地址。将来调用委托时,就“间接”调用了某个方法。为啥不直接调用方法呢?让控件和方法之间有一个“代理人”的角色,这样可以 让控件和方法之间耦合性降低,带来的灵活性。
总结: 委托是一系列方法地址的引用。委托就代理了一系列的方法。调用委托就相当于调用这一系列方法。
委托只所以能代理【一系列】的方法的地址。说明委托肯定实现+=,-=运算符重载。
定义委托
平时用户自定义委托的机会不太多,一般都使用C#自带的委托:
EventHandler、Action, Predicate, Func,…
2.如何定义委托?使用delegate关键字定义
观察一下:委托和方法的形式的区别:a. 没有方法体 b. 方法返回值前多一个delegate关键字。
可以没有返回,可以没有参数。
public delegate void SayHello();
public delegate bool Delegate2(string arg);
3。定义到哪里?
在类内部,在类外部, 但不能在方法内部
4。委托怎么使用?或者怎么调用?
想一想方法怎么调用?和方法调用比较一下。
返回值类型 返回值变量 = 方法名(实参列表);
SayHello(); // 委托不能像方法一样直接调用,为啥?没有方法体, 必须代理某个方法(即实例化)后,再调用。
a. 实例化(让某个委托类型去代理一系列方法地址)
C# 1.0写法
假如把SayHello()当成一个方法的话,Method1是另外一个方法的方法名,相当于方法的参数又是一个方法。在其他语言中,如:javascript,称为回调函数 CallBack。
委托的实例化:是把另外一个方法的方法名,传递到委托构造函数中了。
让sayHello1这个委托的实例,指向了Method1在内存分配的地址。
将来开发者调用sayHello1这个委托实例时,就相当于调用Method1这个方法,从而让需要调用Method1的其他控件和Method1不见面(解耦了)
事件肯定是委托的实例,但委托实例不一定是事件。
SayHello sayHello1 = new SayHello(Method1); // 推荐1、Method1不能添加小括号
public static void Method1()
{
Console.WriteLine("方法1");
}
实例化有一种简写,只要方法满足了委托 (当一个方法,它的返回值和参数列表(参数个数,顺序,类型)和某个委托匹配),就可以直接赋值给委托
SayHello sayHello2 = Method2; // 推荐2
public static void Method2()
{
Console.WriteLine("方法2");
}
b. 使用匿名方法进行实例化,匿名委托本质就是匿名方法(匿名函数:没有名称方法) C# 2.0 写法
C#中匿名方法包括两种:1。匿名委托 2。拉姆达(表达式,语句)
当拉姆达中方法列表中只有一个形参时,()可以省略。
当拉姆达方法体中只有一条语句时,{}可以省略,只要{}省略,return必须省略
SayHello sayHello3 = () => { Console.WriteLine("使用拉姆达表达式"); };
SayHello sayHello3 = () => Console.WriteLine("使用拉姆达表达式");
Delegate2 delegate2 = (arg) => { return true; };
上面的一行代码可以简写成如下代码:
Delegate2 delegate2 = arg => true;
匿名委托(了解)
注意:参数必须设定明确类型,且没有简写形式。
Delegate2 delegate3 = delegate(string arg) { return false; };
Delegate2 delegate22 = delegate (string arg)
{
return arg == "hello";
};
// 代理非匿名方法,此处delegate21不是事件,第一次赋值不能使用+=
Delegate2 delegate21 = Method3;
public static bool Method3(string arg)
{
Console.WriteLine("方法3");
return arg == "hello";
}
多播委托:
多播委托:一个委托实例,同时代理多个方法地址。
a. 语法细节,第一次代理时,不能使用+=,第二次及之后,需要使用+=运算符重载。
b. 注意调用时,执行顺序。
//delegate21 = Method4; //重新赋值,把原来值替换。不叫多播委托。;
delegate21 += Method4; // 多播委托。让一个委托实例,指向多个方法的地址。
delegate21 -= Method3; // 移除一个委托指向
public static bool Method4(string arg)
{
Console.WriteLine("方法4");
return true;
}
// ......
// c. 通过拉姆达实例化委托 C# 3.0 写法
Delegate3 delegate31 = Method5;
Delegate3 delegate32 = (int a, int b) =>
{
return (a - b).ToString();
};
public static string Method5(int a, int b)
{
return (a + b).ToString();
}
5。委托调用
a.委托实例像方法一样调用。
b.使用Invoke()
sayHello1(); // 调用委托,相当于访问了Method1()
sayHello2(); // 调用委托,相当于访问了Method2()
Console.WriteLine("-------------------------");
sayHello1.Invoke();
bool result = delegate22.Invoke("hello");
Console.WriteLine(result);
Console.WriteLine("-------------------------");
// 多播委托调用。方法的执行顺序和委托绑定方法的顺序是一致的。
//delegate21("hello");
bool result2 = delegate21.Invoke("abc");
Console.WriteLine(result2); // 结果拿到最后一个委托的结果。
Console.ReadKey();
}
常见委托:
//Action,Action<T>,Func<T>,Predicate<T>,Converter<T1,T2>,EventHandler
Action<string> action1 = (obj) => { Console.WriteLine("world"); };
Action action2 = () => { };
Func<string> func1 = () => { return "hello"; };
Func<int, int, string, bool> func2 = (a, b, str) =>
{
Console.WriteLine(a);
Console.WriteLine(b);
Console.WriteLine(str);
return false;
};
bool result = func2(10, 20, "hello");
Console.WriteLine(result);
Console.WriteLine(func1.Invoke());
action1.Invoke("abc");
// Arguments参数
// 常见委托的外形:in逆变,out协变
// public delegate void Action();
// public delegate void Action<in T>(T obj);
// public delegate TResult Func<out TResult>();
// public delegate bool Predicate<in T>(T obj);
// public delegate TOutput Converter<in TInput, out TOutput>(TInput input);
// public delegate void EventHandler(object sender, EventArgs e);
// public delegate void EventHandler<TEventArgs>(object sender, TEventArgs e);
二、事件
1。事件概念?
现实中,事件就是发生一件事。
C#语言中的事件:事件是委托的实例(个体),委托的实例不一定是事件,但事件肯定是委托的实例。
事件是一种特殊的委托实例。特殊在哪里?安全的委托实例,受CLR(Common Language RunTime公共语言运行时)管理。
定义事件
定义一个事件。使用event关键字。 EventHandler委托类型 MyClick就是委托实例,即事件变量。
public static event EventHandler MyClick; // 默认值null
给委托赋值
EventHandler click1 = new EventHandler((sender, arg) => { }); // 委托实例,不是事件
3。事件定义的位置?
类内部,不能在方法内部
4。事件实例化(称事件绑定,和委托实例化基本一致。只是第一初始化时,也可以使用+=或-=)
MyClick += Program_MyClick;
MyClick += Program_MyClick1;
MyClick += delegate (object sender, EventArgs arg)
{
Console.WriteLine("匿名委托");
};
MyClick += (sender, arg) =>
{
Console.WriteLine("拉姆达语句");
};
private static void Program_MyClick(object sender, EventArgs e)
{
Console.WriteLine("事件第一次赋值");
}
private static void Program_MyClick1(object sender, EventArgs e)
{
Console.WriteLine("事件第二次赋值");
}
5。调用事件? 人为“立即”调用,在WinForm,一个按钮绑定事件(给事件变量赋值),事件的执行有滞后性,比如:点击时,鼠标进入时,鼠标离开时,…
//MyClick(null, null);
MyClick.Invoke(null, null);
Console.ReadKey();