事件与委托(二)
一、详细内容
事件Event,使用委托的时候,通常会出现两个角色,一个广播者,一个订阅者。
- 广播者,这个类型包含一个委托字段,广播者通过委托来决定什么时候进行广播。
- 订阅者,是方法目标的接受者,订阅者可以决定何时开始或结束监听,方式是通过在委托上调用+=和-=。
- 一个订阅者不知道和不干扰其它的订阅者
- 事件是一种结构,为了实现广播者/订阅者模型,它只暴露了所需的委托特性的部分子集。
- 事件的主要目的就是防止订阅者之间相互干扰。
最简单的声明事件的方式就是在委托前面加上event关键字。
pulic delegate
void
PriceChangedHandler(double oldPrice,double newPrice);
public
class
Brodcaster()
{
pulic event
PriceChangeHandler
PriceChanged;
}
Brodcaster类型里面的代码拥有对PriceChanged的完全访问权,在这里就可以把它当做委托。而Brodcaster类型之外的代码只能对PriceChanged这个event执行+=或-=操作。
(2) 标准事件模式
- system.eventArgs,一个预定义的框架类,出了静态的Empty属性之外,它没有其他成员。
- eventArgs是为事件传递信息的类的基类
public
class
PriceChagnedEventArgs
:
System.EventArgs
{
public
readonly
decimal
OldPrice;
public
readonly
decimal
NewPrice;
public
PriceChangedEventArgs(decimal oldVal,decimal newVal)
{
OldPrice
= oldVal;
NewPrice
= newVal;
}
}
(3) 为事件选择或定义委托
- 返回类型是void;
- 接受两个参数,第一个参数类型是object,第二个参数类型是EventArgs的子类。第一个参数表示事件的广播者,第二个参数包含需要传递的信息;
- 名称必须以EventHandler结尾
(4) system.eventHandler
- Framework定义了泛型委托system.eventHandler,它满足(3)描述的规则。
pulic delegate
void
EventHandler<TEventArgs>(object source,TEventArgs e)where
TEventArgs:EvebtAargs;
可触发事件的protected virtual方法 方法名必须和事件一直,前面再加上On,接收一个EventArgs参数
public
class
Stock
{
public
event
EventHandler<PriceChangedEventArgs>PriceChanged;
protected vivtual void
OnPriceChanged(PriceChangedEventArgs e)
{
if(PriceChanged
!=
null)
PriceChanged(this,e);
}
}
(5) 注意
- 多线程场景下,你需要在测试或调用前,把委托赋值给一个临时变量,来避免线程安全错误:
if(PriceChanged
!=
null)
PriceChanged(this,e);
- 在c#6之后,可以这样写
PriceChanged?.Invoke(this,e);
(6) 非泛型的EventHandler
- 当时间不携带多余信息的时候,可以使用非泛型的EventHandler委托。
- 不需要携带多余信息可以传入EventArgs.Empty属性
OnPriceChanged(EventArgs.Empty);
(7) 事件修饰符
- virtual,可以被重写; abstract,sealed,static.
public
class
Demo
{
public
static
event
EventHandler<EventArgs>
StaticEvent;
public
virtual
event
EventHandler<EventArgs>
VirtualEvent;
}