第13章 事件和索引指示器
事件为类和类的实例提供了向外界发送通知的能力而索引指示器则可以像数组那样对对象进行索引访问在
13.1 事件
事件event 就是类或对象用来发出通知的成员通过提供事件的句柄客户能够把事件和可执行代码联系在一起
public delegate void EventHandler(object sender, EventArgs e);
public class Button: Control
{
public event EventHandler Click;
protected void OnClick(EventArgs e)
{
if (Click != null)
Click(this, e);
}
public void Reset()
{
Click = null;
}
}
13.1.1 事件的声明
attributes event-modifiers event type variable-declarators;
atttributes event-modifiers event type member-name
{ event-accessor-declarations }
事件的修饰符 event-modifier 可以是: new、public、private、protected、internal、static、virtual、sealed、override、abstract
static ,virtual,override 和abstract 修饰符同一时刻只能出现一个。
13.1.2 事件的预订和撤销
在随后的例子中,我们声明了一个使用Button类的登录对话框类。含有两个按钮 OK 和 Cancel 按钮。
public class LoginDialog: Form
{
Button OkButton;
Button CancelButton;
public LoginDialog()
{
OkButton = new Button(...);
OkButton.Click += new EventHandler(OkButtonClick);
CancelButton = new Button(...);
CancelButton.Click += new EventHandler(CancelButtonClick);
}
void OkButtonClick(object sender, EventArgs e)
{
// 处理OkButton.Click 事件
}
void CancelButtonClick(object sender, EventArgs e)
{
// 处理CancelButton.Click 事件
}
}
在例子中使用了Button 类的两个实例事件的预订是通过为事件加上左操作符
+= 来实现的
OkButton.Click += new EventHandler(OkButtonClick);
这样只要事件被触发方法就会被调用
事件的撤消则采用左操作符-=
OkButton.Click -= new EventHandler(OkButtonClick);
如果在类中声明了事件我们又希望像使用域的方式那样使用事件那么这个事件就不能是抽象的也不能显式地包含事件访问声明满足了这两个条件后在任何可以使用域的场合都同样可以使用事件
13.1.3 事件访问器
如Button 的例子所示大多数情况下事件的声明都省略了事件访问声明什么情况下使用事件访问声明呢答案是如果每个事件的存储开销太大我们就可以在类中包含事件访问声明按私有成员的规则存放事件句柄列表
——访问器的声明包括两种添加访问器声明add-accessor-declaration 和删除访问
器声明remove-accessor-declaration
访问器声明之后跟随相关执行代码的语句块在添加访问器声明后的代码需要执行添加事件句柄的操作在删除访问器声明后的代码需要执行删除事件句柄的操作不管是哪种事件访问器都对应相应的一个方法这个方法只有一个事件类型的值参数并且返回值为void
——在执行预订操作时使用添加型访问器在执行撤消操作时使用删除型访问器。访问器中实际上还包含了一个名为value 的隐藏的参数因而访问器在使用局部变量时不能再使用这个名字
class Control: Component
{
// Unique keys for events
static readonly object mouseDownEventKey = new object();
static readonly object mouseUpEventKey = new object();
// Return event handler associated with key
protected Delegate GetEventHandler(object key) {...}
// Add event handler associated with key
protected void AddEventHandler(object key, Delegate handler) {...}
// Remove event handler associated with key
protected void RemoveEventHandler(object key, Delegate handler) {...}
// MouseDown event
public event MouseEventHandler MouseDown
{
add { AddEventHandler(mouseDownEventKey, value); }
remove { AddEventHandler(mouseDownEventKey, value); }
}
// MouseUp event
public event MouseEventHandler MouseUp
{
add { AddEventHandler(mouseUpEventKey, value); }
remove { AddEventHandler(mouseUpEventKey, value); }
}
}
13.1.4 静态事件
- 和域、方法等一样,使用了static修饰符的事件称之为静态事件。静态事件不与具体的实例相关联。因此不能在静态事件的访问器中引用this 关键字。静态事件声明不能能加上 virtual abstract override 修饰符。;;;;非静态事件,我们可以在事件的访问器中使用this 来指代类的实例。
13.2 索引指示器
索引指示器(indexer)使得可以像数组那样对对象使用下标。它为我们提供了通过索引方式方便地访问类的数据信息的方法。
13.2.1 声明
attribute indexer-modifiers indexer-declarator {accessor-declarations}
indexer-modifier 修饰符 new、public、private、protected、internal、virtual、sealed、override、abstract一对 {}之间是索引指示器的访问声明,使用get set 关键字 定义对被索引的元素的读写权限。
程序清单13-4:
using System
class Team
{
string s_name = new string[8];
public string this[int nIndex]
{
get
{
return s_name[nIndex];
}
set
{
s_name[nIndex] = value;
}
}
}
class Test
{
public static void Main()
{
Team t1 = new Team();
for(int i=0; i<6 ;i++)
Console.WriteLine(t1[i]);
}
}
在许多情况下,某些数据信息应该是属于类或类的实例所私有的,需要限制对这些信息的访问。而我们有时又不希望这类数据对外界完全封闭。和属性一样,索引指示器为我们提供了控制访问权限的另一种办法。
13.2.2 实例
根据域名解析IP 地址
程序清单 13-5
13.3 小结
- 在编写类的时候我们可以利用事件向客户说明发生了什么事情事件可以在类的域或属性中加以说明但事件的类型必须是代表型delegate 的我们可以预订事件来保证事件将被触发也可以撤消事件
- 索引指示器使我们可以像使用数组那样为类或类的实例添加路径列表通过下标进行访问类中的信息