委托:就是一个能存放符合某种格式(方法签名)的方法指针的容器。
委托的作用:1.能将方法作为参数和返回值传递; 2.调用一个委托,执行N个方法(多播委托)。
/* 1.声明委托的本质:
* 1.1委托编译后 生成一个 同名类(DGTest)
* 1.2继承关系: DGTest -> MulticastDelegate -> Delegate
*/
public delegate void DGTest();
private void btnTest_Click(object sender, EventArgs e)
{
//语法糖:在C#中有很多 简洁语法,实质是由编译器 在编译时 转成 完整语法,那么这种 简洁语法叫做语法糖
//2.创建委托对象
DGTest dg = Test;//new DGTest(this.Test);
/*3.为委托追加方法的本质:
* 是为 被追加的方法创建一个新的委托对象,并将 方法 指针存入对象的 父类的父类(Delegate)的 IntPtr 变量中
* 然后再将 新创建的委托 添加到 当前委托对象(dg)的 数组中
*/
dg += Test2;//编译后:(DGTest) Delegate.Combine(dg, new DGTest(this.Test2));
dg += Test3;//编译后:(DGTest) Delegate.Combine(dg, new DGTest(this.Test3));
dg -= Test3;//编译后:(DGTest) Delegate.Remove(dg, new DGTest(this.Test3));
/*4.调用委托,其实就是通过调用委托对象里的Invoke方法 遍历 委托内部的数组,然后依次调用 数组中的 方法
*/
dg();//编译后:dg.Invoke();
/* 委托的作用:
* 1.将方法做为参数
* 2.将方法作为返回值
*/
}
void Test()
{
MessageBox.Show("Test");
}
void Test2()
{
MessageBox.Show("Test2");
}
void Test3()
{
MessageBox.Show("Test3");
}
#region 1.0 委托当参数
private void btnPara_Click(object sender, EventArgs e)
{
InvokeTest(Test);
InvokeTest(Test2);
InvokeTest(Test3);
}
/// <summary>
/// 委托当参数使用: 调用 3个 Test 方法 中的某一个
/// </summary>
/// <param name="strType"></param>
public void InvokeTest(DGTest dgTest)
{
dgTest();
}
#endregion
#region 2.0 委托当返回值
private void btnReturn_Click(object sender, EventArgs e)
{
DGTest dg = InvokeTest("1");
dg();
}
/// <summary>
/// 委托当返回值
/// </summary>
/// <param name="strType"></param>
/// <returns></returns>
public DGTest InvokeTest(string strType)
{
switch (strType)
{
case "1":
return Test;
case "2":
return Test2;
default:
return Test3;
}
}
#endregion
#region 3.0 使用泛型方法 加 泛型委托 完成 通用版的 Max方法
/// <summary>
/// 使用泛型方法 加 泛型委托 完成 通用版的 Max方法
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btnFindMax_Click(object sender, EventArgs e)
{
int[] arrInt = new int[5] { 1, 2, 5, 6, 3 };
//int Max = MaxInt(arrInt);
int max = MaxValue<int>(arrInt, (x, y) => x - y);
string[] arrStr = new string[] { "a", "c", "b" };
string maxLengthStr = MaxValue<string>(arrStr, (x, y) => x.Length - y.Length);
Dog[] dogs = new Dog[] { new Dog() { age = 1, name = "小白" }, new Dog() { age = 0, name = "小白2" }, new Dog() { age = 5, name = "小白3" } };
Dog maxAgeDog = MaxValue<Dog>(dogs, (x, y) => x.age - y.age);
}
int MaxInt(int[] arr)
{
int maxInt = arr[0];
for (int i = 1; i < arr.Length; i++)
{
if (maxInt < arr[i])
{
maxInt = arr[i];
}
}
return maxInt;
}
T MaxValue<T>(T[] arr, Comparison<T> func)
{
T maxInt = arr[0];
for (int i = 1; i < arr.Length; i++)
{
//使用委托来 完成元素 大小的比较过程!
if (func(maxInt, arr[i]) < 0)
{
maxInt = arr[i];
}
}
return maxInt;
}
#endregion
委托的缺点: 1.可以 用 Click=null 来清除所有注册的 事件; 2. 可以 用 Click() 来“假冒”事件的触发。
解决
方案,把委托成员做成
private
的,然后增加
AddClickEventHandler
、
RemoveClickEventHandler
两个
public
的方法。
事件: 对委托变量的可访问性进行控制封装。
![](https://img-blog.csdn.net/20140323212918156)
例:利用事件自定义三击鼠标按钮方法
事件: 对委托变量的可访问性进行控制封装。
例:利用事件自定义三击鼠标按钮方法
public delegate void DGMyClick(DateTime time); //定义委托 /// <summary> /// 三击按钮类 - 用户点击三次后 执行用户的 方法 /// </summary> public class MyTripleButton:System.Windows.Forms.Button { Timer time = new Timer(); public MyTripleButton() { base.Click += MyTripleButton_Click; //为父类的 单击事件 注册一个方法(就是 将一个 方法 存入 Click 属性中) time.Interval = 1000; time.Tick += time_Tick; } int clickTimes = 0; //定义一个 用来保存 用户方法的委托对象 /*使用 事件event封装 委托变量,编译后: * 1.会把被修饰的委托变量私有化(private) * 2.会生成一个 与 委托变量 同名的 事件语法,内部包含 add 和 remove方法 * add 和 remove方法内部都是操作 私有的委托变量 * 3.当外部访问 委托变量时,实际上访问的是 同名的事件语法,并使用 += 和 -= 为封装的 私有委托变量 增删方法 */ public event DGMyClick dgMyClick; void time_Tick(object sender, EventArgs e) { clickTimes = 0; } //每当被点击的时候,此方法会被调用 void MyTripleButton_Click(object sender, EventArgs e) { //如果点击次数没达到3次 if (clickTimes < 2) { //如果是第一次点击 则启动计时器 if (clickTimes == 0) { time.Start(); } //点击次数++ clickTimes++; } else//点击三次后 { //1.执行用户的 方法 if (dgMyClick != null) dgMyClick(DateTime.Now); //2.清空点击次数 clickTimes = 0; //3.重启计时器 time.Stop(); } } } public Form1() { InitializeComponent(); //1.创建三击按钮对象 MyTripleButton myBtn = new MyTripleButton(); //2.利用一个事件机制 为 按钮里的委托对象 注册一个 方法(或 移除一个方法) myBtn.dgMyClick += ClickSelf; //3.注意:因为使用了事件机制 封装了 按钮里的委托对象,所以不能 直接 赋值 和 调用委托了 //myBtn.dgMyClick = null; //myBtn.dgMyClick(); this.Controls.Add(myBtn); } void ClickSelf(DateTime time) { MessageBox.Show("三击了~~~~~~~~~~~~~!加分!"); }
委托和事件的区别:委托时类,事件是用来封装“属性封装”的机制
就是一个能存放符合某种格就是一个能存放符合某种格式(方法签名)的方法的指针的容器式(方法签名)的方法的指针的容
就是一个能存放符合某种格式(方法签名)的方法的指针的容器