最近因为工作需要等等原因要开始写.Net code 所以先来学习过一遍C#,感觉还好 ,大学就学习过java感觉差不多吧,但是要对于特殊的机制与特性要重点学习,这就是C#的事件以及委托(关乎到写回到函数的实现)
委托机制:
委托是一个类,它定义了方法的类型,使得可以将方法当作另一个方法的参数来进行传递。事件是一种特殊的委托。
委托的作用:c#中的委托也是为了回调!
四种委托:Delegate,Action ,Func,predicate
Delegate定义:
public delegate int MethodtDelegate(int x, int y);表示有两个参数,并返回int型。
Action定义:
public void Test<T>(Action<T> action,T p)
{
action(p);
}
Action 是无返回值的泛型委托;Action 表示无参,无返回值的委托, Action 至少 0 个参数,至多 16 个参数,无返回值。
Func定义:
public int Test<T1,T2>(Func<T1,T2,int>func,T1 a,T2 b)
{
return func(a, b);
}
Func 是有返回值的泛型委托;Func 表示无参,返回值为 int 的委托;
predicate定义:
public delegate bool Predicate<T> (T obj)
委托特点:
- 委托类似于 C++ 函数指针,但它们是类型安全的。
- 委托允许将方法作为参数进行传递。
- 委托可用于定义回调方法。
- 委托可以链接在一起;例如,可以对一个事件调用多个方法。 方法不必与委托签名完全匹配。
总结一下:
- Delegate 至少 0 个参数,至多 32 个参数,可以无返回值,也可以指定返回值类型
- Func 可以接受 0 个至 16 个传入参数,必须具有返回值
- Action 可以接受 0 个至 16 个传入参数,无返回值
- Predicate 只能接受一个传入参数,返回值为 bool 类型
事件机制:
事件涉及两类角色-事件发布者和事件订阅者。当发生一个事件的时候,事件发布者会发布事件,事件订阅者会接收事件已发生的通知,并且做出相应的处理。其中,触发事件的对象称之为事件发布者,捕获事件并且对其做出处理的称之为事件订阅者。
定义事件:
访问修饰符 event 委托类型 事件名
public event EventHandler birthday
事件订阅者需要订阅事件发布者发布的事件,以便在事件被触发时接收消息并且做出处理。我们可以使用+=来订阅事件,使用-=来
取消订阅事件。
EventHandler只用来处理不包含事件处理的事件。如果我们想在这种方式定义的事件中包含事件数据(传参数或者数据等等),则可以通过派生EventArgs来实现。
如何使用事件:
//第1步,申明一个委托
public delegate int SomeDelegate(string s, bool b);
//第2步,定义符合委托签名(即参数个数与类型一致)的函数。
private int SomeFunction(string s, bool b){...}
//--前2步都相同
//第3步,申明一个的事件,并定义该事件能接受的签名。
public event SomeDelegate SomethingHappened;
//第4步,通过事件来保存符合签名的函数(可以是多个)
myObj.SomethingHappened += new SomeDelegate(SomeFunction);
//第5步,根据需要在适当的时机,运行事件中保存的函数
if( SomethingHappened != null ) {
foreach( SomeDelegate sd in SomethingHappened.GetInvocationList() ) {
int result = sd("somestring", true);
}
}
委托与事件的区别:
(1)C#中事件:事件时属于类的成员,所以要放在类的内部。
(2)委托属于一个定义,是和类、接口类似的,通常放在外部。
(因为大多数委托都要被重用)
委托定义在类里面还是类外面视情况而定,一般定义在与类定义平级部分,且用public修饰,便于外部调用。
若定义在类的内部,则必须通过调用该类的成员才能取得其委托的引用,频繁调用的情况下不合适。
委托与事件的联系:
从事件的声明,我们可以大致看出事件与委托的关系,事件是委托的特殊实现,事件是建立在对委托的语言支持之上的。
委托是一种类型,事件是委托类型的一个实例,加上了event的权限控制,限制权限,只允许在事件声明类里面去invoke和赋值,不允许外面,甚至子类调用。
Delegate.Invoke、Delegate.BeginInvoke And Control.Invoke、Control.BeginInvoke区别
其中Invoke是同步,而BeginInvoke异步
1、Delegate.Invoke (委托同步调用)
a、委托的Invoke方法,在当前线程中执行委托。
b、委托执行时阻塞当前线程,直到委托执行完毕,当前线程才继续向下执行。
c、委托的Invoke方法,类似方法的常规调用。
2、Delegate.BeginInvoke (委托异步调用)
a、委托的BeginInvoke方法,在线程池分配的子线程中执行委托。
b、委托执行时不会阻塞主线程(调用委托的BeginInvoke线程),主线程继续向下执行,毕竟是异步。
c、委托执行时会阻塞子线程。
d、委托结束时,如果有返回值,子线程讲返回值传递给主线程;如果有回调函数,子线程将继续执行回调函数。
1、Control.Invoke (同步调用)
(1)在主线程(UI线程)中调用Control.Invoke
a、在主线程(UI线程)中调用Control.Invoke,先执行Invoke的方法,再执行Invoke后面的代码。
(2)在子线程中调用Control.Invoke
a、子线程中调用Control.Invoke,子线程将调用的方法封装成消息,调用API的RegisterWindowMessage()向UI窗口发送消息。 主线程继续向下执行,子线程处于阻塞状态。
b、当该消息被主线程执行完成后,子线程才能继续往下执行。
2、Control.BeginInvoke (异步调用)
(1)在主线程(UI线程)中调用Control.BeginInvoke
a、在主线程(UI线程)中调用Control.BeginInvoke,将调用的方法封装成消息,调用API的RegisterWindowMessage()向UI窗口发送消息。先执行Invoke后面的代码,再执行Invoke的方法。
(2)在子线程中调用Control.BeginInvoke
a、子线程中调用Control.BeginInvoke,子线程将调用的方法封装成消息,调用API的RegisterWindowMessage()向UI窗口发送消息。主线程继续向下执行,子线程也继续向下执行。
b、最后由主线程执行Invoke的方法。