.Net高级技术 第六章:委托和事件

委托的使用

声明委托的方式:delegate返回值类型委托类型名(参数)

比如delegate void Mydel(int n)

注意这里的除了前面的delegate,剩下部分和声明一个函数一样,但是Mydel不是函数名,而是委托类型名 

存储什么样的方法就声明什么类型(方法参数与返回值)的委托。

声明的委托是一种类型,就像intPerson一样,如果要用的话还要声明委托类型的变量,声明委托类型变量的方式:Mydel f1;

将委托类型变量指向函数 Mydel sp = new Mydel (SayHello),这样就可以像调用普通函数一样把sp当成函数用了。委托可以看做是函数的指针。整数可以用整数变量指向它,对象可以用对象变量指向它,函数也可以用委托变量指向它。和直接调用函数的区别:用委托就可以指向任意的函数,哪怕是之前没定义的都可以,而不使用受限于那几种。

将委托类型变量指向函数还可以简化成Mydel sp = SayHello,编译器帮我们进行了new。但是不能sp=PrintIt(),因为这样就成了函数调用。

 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace _01委托
{
    delegate void MyDelegate();
    class Program
    {
        static void Main(string[] args)
        {
            Test2(Test1);
            Console.ReadKey();
        }

        static void Test1()
        {
            Console.WriteLine("我是test1");
        }
        static void Test2(MyDelegate fun)
        {
            fun();
            Console.WriteLine("我是test2");
        }
    }
}

 

匿名方法

 

使用Delegate的时候很多时候没必要使用一个普通的方法,因为这个方法只有这个Delegate会用,并且只用一次,这时候使用匿名方法最合适。

 

匿名方法就是没有名字的方法。3就是没有名字的int对象。3+5就是两个匿名int对象的相加,允许匿名对象,就允许匿名方法。

 

 ProcessWordDelegate p = delegate(string s)

 

            {

 

                Console.WriteLine(s);

 

            };

 

知道C#中有匿名方法,看到这种写法知道是匿名函数即可。

 

匿名方法与lambda表达式最终编译为一个方法。

多播委托(委托链,委托的组合)

 

delegate void ProcessWordDelegate(string s)

 

ProcessWordDelegate d = new ProcessWordDelegate(SayHello)+new ProcessWordDelegate(ToLower)

 

多播委托如何处理返回值?

 

委托绑定多个方法后,其中一个方法执行发生异常后面的方法还会继续执行吗?不会!

 

一个重要的方法GetInvocationList();//返回一个Delegate[]类型。Delegate类是一个抽象类,是所有委托的父类。

 

组合的委托必须是同一个类型

 

相当于创建了一个按照组合的顺序依次调用的新委托对象。

 

委托的组合一般是给事件用的,用普通的委托的时候很少用

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace _02委托
{
    class Program
    {
        delegate void MyDelegate(string name);
        delegate string NewDelegate(string name);
        static void Main(string[] args)
        {
            Console.WriteLine("====== 委托 ======");
            DoWork("委托", SayChinese);
            DoWork("delegate", SayEnglish);

            Console.WriteLine("====== 多播委托 ======");
            //MyDelegate dg = new MyDelegate(SayChinese);
            MyDelegate dg = SayChinese;
            dg += SayEnglish;
            if (dg!=null)
            {
                DoWork("yokin", dg);
            }

            Console.WriteLine("====== 匿名委托 ======");
            MyDelegate md = delegate(string name){ Console.WriteLine("哈哈,我是" + name); };
            DoWork("匿名委托", md);

            Console.WriteLine("====== 拉姆达表达式 ======");
            MyDelegate md2 = (string name) => { Console.WriteLine("哈哈,我是" + name); };
            DoWork("拉姆达表达式", md2);

            NewDelegate nw = (name) => { return "不是吧," + name + "也可以!"; };
            string tips = nw("这样");
            Console.WriteLine(tips);

            Console.ReadKey();
        }
        static void DoWork(string name,MyDelegate fun)
        {
            fun(name);
        }
        static void SayChinese(string name)
        {
            Console.WriteLine("你好,"+name+"!");
        }
        static void SayEnglish(string name)
        {
            Console.WriteLine("Hello," + name + "!");
        }
    }
}

 

 

  窗体传值——委托

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace 窗体传值
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void btnSend_Click(object sender, EventArgs e)
        {
            Form2 f2 = new Form2(txtSend.Text, SetValues);
            f2.Show();
        }

        public void SetValues(string name)
        {
            txtSend.Text = name;
        }
    }
}

  

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace 窗体传值
{
    public delegate void Mydelegate(string name);
    public partial class Form2 : Form
    {
        public Form2()
        {
            InitializeComponent();
        }
        public Mydelegate _md;
        public Form2(string name,Mydelegate md):this()
        {
            txtBack.Text = name;
            this._md = md;
        }

        private void btnBack_Click(object sender, EventArgs e)
        {
            if (this._md!=null)
            {
                this._md(txtBack.Text);
                this.Close();
            }
        }
    }
}

  

 

事件(通过委托实现的,委托才是事件能正常执行的核心内容)

事件语法:event ProcessWordDelegate 例子 OnInt

加了event关键字实现事件机制的好处:用了event事件,不可以修改事件已经注册的值;不可以冒充进行事件通知了。在IntUC类外部就不能通过OnInt(3)的方式调用注册的委托了。只能+=-=

 

课上练习:实现连续点击三次触发TriClick事件的按钮(用UserControl),用EventHandler这个委托就行。注意不要把判断次数的代码写到用控件的窗口上,否则就违反了封装的原则。

动态设置控件事件

 

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace 窗体传值_事件
{
    public delegate void MyDelegate(string name);
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        public event MyDelegate _md;
        private void button1_Click(object sender, EventArgs e)
        {
            Form2 f2 = new Form2();
            this._md += f2.SetText;
            if (this._md!=null)
            {
                this._md(textBox1.Text);
                f2.Show();
            }
        }
    }
}

  

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace 窗体传值_事件
{
    public partial class Form2 : Form
    {
        public Form2()
        {
            InitializeComponent();
        }

        public void SetText(string name)
        {
            textBox1.Text = name;
        }
    }
}

  

 

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace 窗体传值_系统事件
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        public event EventHandler evt;
        private void button1_Click(object sender, EventArgs e)
        {
            Form2 f2 = new Form2();
            this.evt += f2.SetText;
            MyEventArgs mea=new MyEventArgs();
            mea.Name=textBox1.Text;
            if (this.evt!=null)
            {
                this.evt(this, mea);
            }
            f2.Show();
        }
    }

    public class MyEventArgs : EventArgs
    {
        public string Name { get; set; }
    }
}

  

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace 窗体传值_系统事件
{
    public partial class Form2 : Form
    {
        public Form2()
        {
            InitializeComponent();
        }

        public void SetText(object sender, EventArgs e)
        {
            MyEventArgs mea = e as MyEventArgs;
            textBox1.Text = mea.Name;
        }
    }
}

  

 委托和事件的区别

委托和事件没有可比性,因为委托是数据类型,事件是对象(可以理解为对委托变量的封装。),下面说的是委托的对象(用委托方式实现的事件)和(标准的event方式实现)事件的区别。事件的内部是用委托实现的。(举例子:三种实现事件方式的区别(直接用委托实现、用私有委托+公有方法模拟事件,直接用event事件实现))

因为对于事件来讲,外部只能“注册自己+=、注销自己-=”,外界不可以注销其他的注册者,外界不可以主动触发事件,因此如果用Delegate就没法进行上面的控制,因此诞生了事件这种语法。addremove

事件是用来阉割委托实例的。事件只能addremove自己,不能赋值。事件只能+=-=,不能=、不能外部触发事件。

 委托与事件总结

委托的作用: 占位,在不知道将来要执行的方法的具体代码时,可以先用一个委托变量来代替方法调用(委托的返回值,参数列表要确定)。在实际调用之前,需要为委托赋值,否则为null。 事件的作用: 事件的作用与委托变量一样,只是功能上比委托变量有更多的限制。(比如:1.只能通过+=或-=来绑定方法(事件处理程序)2.只能在类内部调用(触发)事件。) 在自定义控件(自己编写控件的时候,会大量用到.编写控件的时候,会写一些事件。但是当这些事件 被触发以后,具体执行的那些事件处理程序是编写控件的人没法确定的。这个时候只能通过事件来占位(调用),具体调用的是哪个方法,由使用控件的人来决定(Click+=new 委托(方法名);))

 

posted @ 2015-05-16 11:30  linyongqin  阅读(131)  评论(0编辑  收藏  举报