1.5 内置委托
上述几种委托的使用,都没能离开定义委托类型这一步骤。微软干脆直接把定义委托这一步骤封装好,形成三个泛型类:Action、Func和Predicate,这样就省去了定义的步骤,推荐使用。
C#
public class Program { public static void Main(string[] args) { //Action Actionstring> action = delegate(string str) { Console.WriteLine("你好!" + str); }; action("GG"); //Func Funcint, int, int> func = delegate(int x, int y) { return x + y; }; Console.WriteLine("计算结果:" + func(5, 6)); //Predicate Predicatebool> per = delegate(bool isTrue) { return isTrue == true; }; Console.WriteLine(per(true)); } } |
它们的区别如下:
Action委托:允许封装的方法有多个参数,不能有返回值;
Func委托:允许封装的方法有多个参数,必须有返回值;
Predicate委托:允许封装的方法有一个参数,返回值必须为bool类型。
2. 事件
委托是一种类型,事件依赖于委托,故事件可以理解为是委托的一种特殊实例。它和普通的委托实例有什么区别呢?委托可以在任意位置定义和调用,但是事件只能定义在类的内部,只允许在当前类中调用。所以说,事件是一种类型安全的委托。
2.1 定义事件
通过一个简单的场景来演示下事件的使用:
C#
/// /// 音乐播放器 /// public class MusicPlayer { //step01:定义 音乐播放结束 事件 public event EventHandler PlayOverEvent; public string Name { get; set; } public MusicPlayer(string name) { this.Name = name; } //step02:定义一个触发事件的方法 public void PlaySong() { //模拟播放 Console.WriteLine("正在播放歌曲:" + this.Name); for (int i = 0; i 20; i++) { Console.Write("."); Thread.Sleep(100); } //播放结束,则触发PlayOverEvent事件 if (PlayOverEvent != null) { PlayOverEvent(this, null); } } } public class Program { static void Main(string[] args) { //创建音乐播放器对象 MusicPlayer player = new MusicPlayer("自由飞翔"); //step03:注册事件 player.PlayOverEvent += player_PlayOverEvent; //播放歌曲,结束后触发事件 player.PlaySong(); Console.ReadKey(); } static void player_PlayOverEvent(object sender,EventArgs e) { MusicPlayer player = sender as MusicPlayer; Console.WriteLine("rn{0}播完了!", player.Name); } } |
程序运行结果:
(1)总结上面事件使用的几个步骤:
step01:用event关键字定义事件,事件必须要依赖一个委托类型;
step02:在类内部定义触发事件的方法;
step03:在类外部注册事件并引发事件。
(2)public event EventHandler PlayOverEvent
这句代码在MusicPlayer类定义了一个事件成员PlayOverEvent,我们说事件依赖于委托、是委托的特殊实例,所以EventHandler肯定是一个委托类型。下面我们来验证一下:
EventHandler是微软封装好的事件委托,该委托没有返回值类型,两个参数:sender事件源一般指的是事件所在类的实例;TEventArgs事件参数,如果有需要创建,要显示继承System.EventArgs。
2.2 事件的本质
C#
MusicPlayer player = new MusicPlayer("自由飞翔");
//注册事件
player.PlayOverEvent += player_PlayOverEvent;
player.PlaySong();
从上面代码我们观察到,事件要通过”+=”符号来注册。我们猜想,事件是不是像多播委托一样通过Delegate.Combine方法可以绑定多个方法?还是通过反编译工具查看下:
我们看到PlayOverEvent事件内部生成了两个方法:add_ PlayOverEvent和remove_ PlayOverEvent。add方法内部调用Delegate.Combine把事件处理方法绑定到委托列表;remove方法内部调用Delegate.Remove从委托列表上移除指定方法。其实,事件本质上就是一个多播委托。