---------------------- ASP.Net+Android+IOS开发、.Net培训、期待与您交流! ----------------------
委托与事件
1、委托
委托是一种引用方法的类型,委托类型派生自.NET Framework 中的Delegate类,它是密封的,不能从Delegate中派生委托类型,也不能从中派生自定义类型。与委托的签名(由返回类型和参数构成)匹配的任何方法都可以分配给委托,这样既可通过编程的方式来更改方法的调用,也可以实现在现有类中插入代码(既通过委托传递方法)。
delegate void EventHandler(object sender,EventArgs e)
委托具有以下特点:
(1)类型安全
(2)允许将方法当做参数传递
(3)可用于定义回调方法
(4)可以链接在一起(可以对一个事件调用多个方法)
(5)方法不需要与委托签名精准匹配
说到委托,不得不说匿名方法,委托提供运算符和方法来添加或者删除目标方法,可以广泛地应用于事件、回掉、异步调用、多线程等,然而有时候仅仅为了使用一个委托,不得不创建一个类或方法,这个时候就可以用到匿名方法。
class SomeClass
{
delegate void SomeDelegate();
public void Fun()
{
SomeDelegate del = delegate() { Console.WriteLine("我是一个匿名方法,通过委托调用"); };
}
}
匿名方法被定义为内嵌方法,而不是作为任何类的成员,此外无法将方法属性应用到匿名方法,且匿名方法也不能定义一般类型或添加一般约束。如果匿名方法需要参数,则方法签名必须与其指派的委托定义相匹配,如同一个正常方法,例子:
class SomeClass
{
delegate void SomeDelegate(string str);
public void Fun()
{
SomeDelegate del = delegate(string str)
{ Console.WriteLine("我是一个匿名方法,传入了一个参数 "+str); };
}
}
匿名方法还可以直接当作参数传递(委托允许将方法当作参数传递,这个方法可以是匿名方法),例子:
class MyClass
{
public void MyThread()
{
Thread NewThread = new Thread(delegate() { Console.WriteLine("把方法当作参数传递,开启新线程"); });
}
}
如果忽略delegate关键字后面的空括号,则定义一种特殊的匿名方法,他可以指派给任何委托,不管该委托是什么签名。 例子:
class MyClass
{
delegate void SomeDelegate(string str);
delegate void SomeDelegate();
public void Fun()
{
SomeDelegate del1 = delegate { Console.WriteLine("delegate关键字后不加括号,则我可以指派给任何委托"); };
SomeDelegate del2 = delegate { Console.WriteLine("delegate关键字后不加括号,则我可以指派给任何委托"); };
}
}
注意一点,委托类型名字可以一样(只要签名不同就不算同一个委托)。委托还可以定义一般参数”如同泛型“,例子:
class SomeClass<T>
{
delegate void SomeDelegate<T>(T t);
public void Func(T t)
{
SomeDelegate<int> del = delegate(int num)
{
Console.WriteLine(num);
};
del(123);
}
}
委托推理:
当将一个方法名指派给委托时,编译器首先推理该委托的类型,然后根据方法名检验他们的签名是否一致,然后会创建这个类型的实例,并把方法添加进调用列表。所以可以直接指派方法名给委托,而不必new一个委托对象,编译器自动为我们做了这些事。
class Class1
{
delegate void SomeDelegate(ref int i);
public static void Func(ref int i)
{
if (i <= 0) return;
for (int j = 0; j < i; j++)
{
SomeDelegate del = Func;
Console.WriteLine(i);
i--;
del(ref i);
}
}
static void Main(string[] args)
{
int num = 5;
Func(ref num);
Console.ReadKey();
}
}
委托还可以传递方法来回调,如窗体的通信例子:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private string str;//主窗体的私有字段
private void Func(string str)//主窗体的私有方法,等下会在新窗体中回调;
{
MessageBox.Show(str);
}
private void button1_Click(object sender, EventArgs e)
{
NewFrm frm = new NewFrm();
frm.str = this.str;//把主窗体的字段传递到新窗体
frm.Del = Func;//相当于授权(传递方法),授权给NewFrm对象的Del变量(委托变量)
frm.Show();
}
}
//新窗体类
public partial class NewFrm : Form
{
public NewFrm()
{
InitializeComponent();
}
public string str;
delegate void SomeDelegate(string str);
public SomeDelegate Del;
private void button1_Click(object sender, EventArgs e)
{
if (Del != null)
{
Del(str);
}
}
}
委托还可以实现多线程,例子:
class MyClass
{
static void Fun1()
{
for (int i = 0; i < 100000; i++)
{
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine(i);
}
}
static void Fun2()
{
for (int i = 0; i < 10000; i++)
{
Console.ForegroundColor = ConsoleColor.Blue;
Console.WriteLine(i);
}
}
static void Fun3()
{
for (int i = 0; i < 10000; i++)
{
Console.ForegroundColor = ConsoleColor.Yellow;
Console.WriteLine(i);
}
}
static void Main(string[] args)
{
//public Thread(ThreadStart start);这是Thread类定义的构造函数
//public delegate void ThreadStart();ThreadStart其实就是一个委托类型
Thread f1 = new Thread(Fun1);
Thread f2 = new Thread(Fun2);
Thread f3 = new Thread(Fun3);
f1.Start();
f2.Start();
f3.Start();
}
}
2、事件
事件是类在发生其关注的事情时用来提供通知的一种方式”这种通知称为引发事件,引发事件的对象称为事件源,通常可以作为参数传递给方法(当然还可以定义一些其他参数传递过去),事件使用委托来为触发时需要调用的方法提供类型安全的封装,当事件触发时,调用该委托,即调用绑定到委托的方法(事件其实就是委托变量)。例子:
public partial class MainFrm : Form //主窗体
{
Form1 frm = new Form1();//Form1是主窗体的一个字段,相当于一个Button控件的样子
public MainFrm()
{
frm.Show();
InitializeComponent();
frm.MyEvent += this.Func;//绑定方法
}
public void Func(string str)
{ MessageBox.Show(str); }
}
//为Form1添加了一个自定义事件
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private string str = "我是事件参数";
public delegate void MyDelegate(string str);
public event MyDelegate MyEvent;
private void button1_Click(object sender, EventArgs e)
{
if (MyEvent == null)
return;
MyEvent(str);//当调用button1_Click方法时触发该自定义事件(点击按钮时调用绑定到该事件的方法)
}
}
可以看到,事件其实也是一种方法的传递。触发事件前应先判断是否订阅了事件,订阅事件其实就是绑定方法。在上例中MainFrm订阅了事件。
if (MyEvent == null)
return;//其实就是判断该事件是否订阅了
还可以使用事件访问器声明事件(即添加、移除方法),例子:
delegate void TestEventDelegate(object o,EventArgs e);
class EventSource
{
private TestEventDelegate TestEventHandlers;
public event TestEventDelegate TestEvent
{
add
{
lock (TestEventHandlers)
{
TestEventHandlers += value;
}
}
remove
{
lock (TestEventHandlers)
{
TestEventHandlers -= value;
}
}
}
private void RaiseTestEvent()
{
if (TestEventHandlers != null)
{
TestEventHandlers(this, new System.EventArgs());
}
}
}
---------------------- ASP.Net+Android+IOS开发、.Net培训、期待与您交流! ----------------------