.net高级应用——委托

来源:互联网 发布:西门子plc编程语言 编辑:程序博客网 时间:2024/06/06 09:55
回调(CALL BACK)函数是WINDOWS编程的一个重要部分.VB.NET中添加了AddressOf关键字后,开发人员可以利用以前一度受到限制的API了.回调函数实际上是方法调用的指针,也称为函数指针.在.NET中,以委托的形式实现了函数指针的概念.与C相比, .NET的委托是类型安全的.比如:有以前几种情况会用到委托:启动线程,通用库类,事件.
我准备用C#来回忆一下委托的实现及相关知识.
在C#中声明委托有两个步骤,如下:
<1>.定义要使用的委托,告诉编译器这种类型的委托代表了哪种类型的方法,如:
delegate void ShowServerStatus(string str);
<2>创建该委托的一个或多个实例,如:
ShowServerStatus Test=new ShowServerStatus(param /*这个参数是方法名称,
其函数签名必须与委托一样,此处应该是返回型为void的,带一个string参数的方法名称*/);

理解与提示:
<1>.理解委托的一个要点是它们的类型安全性非常高,在定义委托时,必须给出它所代表
的方法的全部细节.
<2>.理解委托的一个好方式是把委托的作用当作是给方法签名指定名称.
<3> .注意: 在C#中,委托在语法上总是带有一个参数的构造函数.这个函数就是委托引用的方法.
下面用例子来说明第三点:
private delegate string GetStringValue();

static void Main(string[] args)
{
int x=90;
GetStringValue Test=new GetStringValue(x.ToString);
//注意,上面是x.ToString,而不是x.ToString().同时,必须注意到,由于
调用到委托的这个方法,即Main()是Static的,所以委托中,只能把静态的
方法名作为参数传给 委托类,而不能把实例方法名作为参数传递给委托类作为参数.

Console.WriteLine("String is :"+Test);
//注意,Test是委托类GetStringValue的对象,由于其返回类型是string型,
故可以作为控制台的输出参数
}

匿名方法使用委托:
以上介绍了要使委托工作,方法必须已经存在,即委托是用方法的签名定义的,但使用委托还有另外一种方式,即通过匿名方法.匿名方法是用作委托参数的一个代码块.以下例子简单介绍一下匿名方法使用委托:
delegate string delegateTest(string val);

static void Main(string[] args)
{
string mid=",middle part.";
delegateTest anon=delegate(string param)
{
param+=mid;
param+="and this was added to the string.";
return param;
}
Console.WriteLine(anon("Start of string"));
}

以上使用方法级的string变量mid,该变量是在匿名方法的外部定义的,并添加到要传送的参数中.接着代码返回此字符串值.在调用委托时,把一个字符串传送为参数,将返回的字符串输出到控制台上.
匿名方法的优点是减少了系统开销,方法仅在由委托使用时才定义.在使用匿名方法时,必须遵循两个规则:
<1>.在匿名方法中不能使用跳转语句跳到该匿名方法的外部.
<2>.匿名方法外部的跳转语句不能跳到该匿名方法的内部.


<二>

委托数组的运用,如下例:
class program
{
delegate double DoubleOp(double x);

static double multi(double value)
{
return value*2;
}

static double square(double value)
{
return value*value;
}

static void ProcessAndDisplay(DoubleOp action,double value)
{
double result=action(value);
Console.WriteLine("Value is {0},result of operation is {1}",value,result);
}

static void Main()
{
DoubleOp[] operations={new DoubleOp(multi),new DoubleOp(square)}; 
for(int index=0;index<operations.Length;index++)
{
ProcessAndDisplay(operations,2.0);
ProcessAndDisplay(operations,29.05);
ProcessAndDisplay(operations,28.08);
Console.WriteLine();
}
}
}

多播委托,委托也可以包含多个方法,这种委托称为多播委托.如果调用多播委托,就可以按顺序连续调用多个方法.为此,委托的签名就必须返回void,实际上,编译器发现某个委托返回void,就会自动假定这是一个多播委托.示例如下:
DoubleOp operation1=new DoubleOp(multi);
DoubleOp operation2=new DoubleOp(square);
DoubleOp operation3=operation1+operation2;

多播委托还识别运算符-和-=,以从委托中删除方法调用. 
多播委托是一个派生于System.MulticastDelegate的类,System.MulticastDelegate又派生于基类
System.Delegate. System.MulticastDelegate其他成员允许把多个方法调用链接在一起,成为一个列表.

如果使用多播委托,就应注意到同一个委托调用方法链的顺序并未正式定义.因此应避免编写依赖于以任意特定顺序调用方法的代码.

委托在线程中的运用:
众所周知,线程是不安全的,在线程中执行程序,需要给他提供一个安全的处理方式.于是就用到了委托.

先声明一个委托方法类:

private delegate void ShowOnServerStatus(string str);

处理的代码(要被委托的方法):

private void ShowOnServer(string str)

{

textbox3.AppendText(str+"\r\n");

}

启动一个线程:


Thread thre = new Thread(new ThreadStart(accp));

thre.Start();

线程要处理的方法accp():


private void accp()

{


if (textBox3.InvokeRequired) //为了线程中的安全.

{
//定义委托方法对象d,並指派showOnserver给这个委托的方法.
ShowOnServerStatus d = new ShowOnServerStatus(showOnserver);

this.Invoke(d, "主机开始监听....\r\n");
//执行这个委托的方法.

}

}