C#委托(Delegate)事件(Event)应用详解 (原)
委托 (Delegate)
委托是一种定义方法签名的类型,可以与具有兼容签名的任何方法关联。您可以通过委托调用方法。委托用于将方法作为参数传递给其他方法。事件处理程序就是通过委托调用的方法。与委托的签名匹配的任何可访问类或结构中的任何方法都可以分配给该委托。方法可以是静态方法,也可以是实例方法。这样就可以通过编程方式来更改方法调用,还可以向现有类中插入新代码。只要知道委托的签名,就可以分配您自己的方法。
多播委托(Multi-Broadcast Delegate)
多播委托是指引用多个方法委托。当调用委托时,它连续调用每个方法。为了把委托的单个实例合并为一个多播委托,委托必须是同类型的,返回类型必须是void,不能带输出参数(但可以带引用参数),如果委托是有返回值的函数,则只能调用最后一个委托函数。 除此之外,它们的声明和实例化都和其他委托没有什么不同。多播委托用于C#的事件模型中。您可以把多播委托看作两个或多个标准委托串在一起。委托可以使用算术运算符+和+=串在一起。委托也能使用-和-=运算符从多播委托中删除。当调用多播委托里,委托所表示的每个方法依次调用。如果有任何参数,它们将用于所有的方法。
源代码:
using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using System.Threading;
namespace CSFramework.Tech.Delegate
{
//测试用例
public class TestClasses
{
//测试委托
public void TestDelegate()
{
A a = new A();
B b = new B();
b.SetDelegateMethod(a.A_Method); //给A对象设置一个委托,该委托是委托A对象内的A_Method方法
b.TestDelegate(); //测试这个委托。注意提示信息
}
//测试事件
public void TestEvent()
{
A a = new A();
B b = new B();
//给b对象的MyEven事件绑定一个委托方法,该委托是委托A对象内的A_Method方法
b.MyEven += new MethodInvoke(a.A_Method);
b.TestEvent(); //测试这个事件。注意提示信息
}
//测试多播
public void TestMultiBroadcast()
{
A a = new A();
B b = new B();
b.MyEven += new MethodInvoke(a.A_Method); //给b对象的MyEven事件绑定一个委托方法A_Method
b.MyEven += new MethodInvoke(a.AA_Method); //给b对象的MyEven事件绑定一个委托方法AA_Method
b.TestEvent(); //测试这个事件。注意提示信息
}
private WriteLogMethod _logMethod = null;
private Form _owner = null;
//测试线程内调用委托
public void TestDelegateInThread(Form owner,WriteLogMethod method)
{
_logMethod = method;
_owner = owner;
Thread t = new Thread(new ThreadStart(Run));
t.Start();//开始运行线程
}
//多线程内的方法
private void Run()
{
//
//直接调用_logMethod()试试? 会抛出异常:
//Cross-thread operation not valid: Control ''''listBox1'''' accessed from a thread other than the thread it was created on.
//
/*
_logMethod("多线程内的输出数据1");
_logMethod("多线程内的输出数据2");
_logMethod("多线程内的输出数据3");
*/
// Control.Invoke()方法说明:
// Executes the specified delegate, on the thread that owns the control''''s underlying
// window handle, with the specified list of arguments.
//
_owner.Invoke(_logMethod, "多线程内的输出数据1");
_owner.Invoke(_logMethod, "多线程内的输出数据2");
_owner.Invoke(_logMethod, "多线程内的输出数据3");
}
}
/// <summary>
/// 定义一个由多线程调用的委托类型.用于显示多线程内输出的数据.
/// </summary>
public delegate void WriteLogMethod(string log);
/// <summary>
/// 定义一个自定义委托类型
/// </summary>
public delegate void MethodInvoke();
//测试类A
public class A
{
public void A_Method()
{
MessageBox.Show("A对象内的A_Method方法!");
}
public void AA_Method()
{
MessageBox.Show("A对象内的AA_Method方法!");
}
}
//测试类B
public class B
{
public void B_Method()
{
MessageBox.Show("B对象内的方法!");
}
//委托方法变量
private MethodInvoke _delegateMethod;
public void SetDelegateMethod(MethodInvoke method)
{
_delegateMethod = method;
}
//测试由外部传进来的委托事件.
public void TestDelegate()
{
if (_delegateMethod != null) _delegateMethod();
}
//事件变量
private event MethodInvoke _MyEvent = null;
/// <summary>
/// 给对象定义一个事件。
/// 注意事件定义的标准语法,add,remove
/// </summary>
public event MethodInvoke MyEven
{
add { _MyEvent += new MethodInvoke(value); }
remove { _MyEvent -= new MethodInvoke(value); }
}
//测试对象的事件。
public void TestEvent()
{
if (_MyEvent != null) _MyEvent();
}
}
}
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using System.Threading;
namespace CSFramework.Tech.Delegate
{
//测试用例
public class TestClasses
{
//测试委托
public void TestDelegate()
{
A a = new A();
B b = new B();
b.SetDelegateMethod(a.A_Method); //给A对象设置一个委托,该委托是委托A对象内的A_Method方法
b.TestDelegate(); //测试这个委托。注意提示信息
}
//测试事件
public void TestEvent()
{
A a = new A();
B b = new B();
//给b对象的MyEven事件绑定一个委托方法,该委托是委托A对象内的A_Method方法
b.MyEven += new MethodInvoke(a.A_Method);
b.TestEvent(); //测试这个事件。注意提示信息
}
//测试多播
public void TestMultiBroadcast()
{
A a = new A();
B b = new B();
b.MyEven += new MethodInvoke(a.A_Method); //给b对象的MyEven事件绑定一个委托方法A_Method
b.MyEven += new MethodInvoke(a.AA_Method); //给b对象的MyEven事件绑定一个委托方法AA_Method
b.TestEvent(); //测试这个事件。注意提示信息
}
private WriteLogMethod _logMethod = null;
private Form _owner = null;
//测试线程内调用委托
public void TestDelegateInThread(Form owner,WriteLogMethod method)
{
_logMethod = method;
_owner = owner;
Thread t = new Thread(new ThreadStart(Run));
t.Start();//开始运行线程
}
//多线程内的方法
private void Run()
{
//
//直接调用_logMethod()试试? 会抛出异常:
//Cross-thread operation not valid: Control ''''listBox1'''' accessed from a thread other than the thread it was created on.
//
/*
_logMethod("多线程内的输出数据1");
_logMethod("多线程内的输出数据2");
_logMethod("多线程内的输出数据3");
*/
// Control.Invoke()方法说明:
// Executes the specified delegate, on the thread that owns the control''''s underlying
// window handle, with the specified list of arguments.
//
_owner.Invoke(_logMethod, "多线程内的输出数据1");
_owner.Invoke(_logMethod, "多线程内的输出数据2");
_owner.Invoke(_logMethod, "多线程内的输出数据3");
}
}
/// <summary>
/// 定义一个由多线程调用的委托类型.用于显示多线程内输出的数据.
/// </summary>
public delegate void WriteLogMethod(string log);
/// <summary>
/// 定义一个自定义委托类型
/// </summary>
public delegate void MethodInvoke();
//测试类A
public class A
{
public void A_Method()
{
MessageBox.Show("A对象内的A_Method方法!");
}
public void AA_Method()
{
MessageBox.Show("A对象内的AA_Method方法!");
}
}
//测试类B
public class B
{
public void B_Method()
{
MessageBox.Show("B对象内的方法!");
}
//委托方法变量
private MethodInvoke _delegateMethod;
public void SetDelegateMethod(MethodInvoke method)
{
_delegateMethod = method;
}
//测试由外部传进来的委托事件.
public void TestDelegate()
{
if (_delegateMethod != null) _delegateMethod();
}
//事件变量
private event MethodInvoke _MyEvent = null;
/// <summary>
/// 给对象定义一个事件。
/// 注意事件定义的标准语法,add,remove
/// </summary>
public event MethodInvoke MyEven
{
add { _MyEvent += new MethodInvoke(value); }
remove { _MyEvent -= new MethodInvoke(value); }
}
//测试对象的事件。
public void TestEvent()
{
if (_MyEvent != null) _MyEvent();
}
}
}
如果委托是有返回值的函数,则只能调用最后一个委托函数:
//测试有返回值的多播。
public void TestReturnValueEvent()
{
A a = new A();
B b = new B();
//产生有返回值的多播事件
b.ReturnValueEvent += new GetValueInvoke(a.GetValueA); //注:GetValueA()函数返回int 100
b.ReturnValueEvent += new GetValueInvoke(a.GetValueB); //注:GetValueB()函数返回int 200
b.TestEvent1(); //显示结果200; =a.GetValueB();
A a1 = new A();
B b1 = new B();
//产生有返回值的多播事件- 顺序相反
b1.ReturnValueEvent += new GetValueInvoke(a1.GetValueB); //注:GetValueB()函数返回int 200
b1.ReturnValueEvent += new GetValueInvoke(a1.GetValueA); //注:GetValueA()函数返回int 100
b1.TestEvent1(); //显示结果100; =a1.GetValueA();
}
证明:有返回值的函数用于多播是失败的!
结合测试用例思考:
为什么b.SetDelegateMethod()与b.MyEven += new MethodInvoke(a.A_Method)显示结果一致,但有什么区别呢?
解释:b.SetDelegateMethod()是调用SetDelegateMethod方法给b对象内的_delegateMethod变量赋值。
而b.MyEven += new MethodInvoke(a.A_Method)是给b.MyEven事件绑定一个MethodInvoke类型方法。使用"+="操作符表示给b.MyEven事件同时绑定多个方法,这就是C#内的多播应用。
因此b.SetDelegateMethod()是调用方法而b.MyEven += new MethodInvoke(a.A_Method)是给事件绑定方法。
如转载请注明出处: www.csframework.com C/S框架网