委托
Posted Chris_在IT道路上前行
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了委托相关的知识,希望对你有一定的参考价值。
本章要讨论回调函数。回调函数是一种非常有用的编程机制,它的存在已经有很多年了。
Microsoft .Net Framework通过委托(delegate)来提供了一种回调函数机制。
列如:委托确保回调方法是类型安全的。委托还允许顺序调用多个方法,并支持调用静态方法和实例方法。
C#中委托是在程序运行时可以使用它们来调用不同的函数。
举个简单的例子,你是编程的,你现在正在写一个ASP.NET网页,而JS是你不熟悉的,于是你委托你的一位同事来帮助你完成JS部分。这就是委托,把你所不能做的事情交给其他人去做。
1.简单的委托http://www.cnblogs.com/birdshover/archive/2008/01/07/1029471.html
那么委托需要承载哪些信息呢?首先它存储了方法名,还有参数列表(方法签名),以及返回类型,比如:
delegate String/*返回类型*/ ProcessDelegate(Int32 i);
蓝色部分是声明委托的关键字,红色是返回类型,黑色部分是委托的类型名,()里的就是参数部分。你要使用这个委托来做事情,必须满足一下条件:
- 返回类型和委托的返回类型一致,这里是String类型
- 参数列表能且只能有一个参数,并且是Int32类型
例如:
输出的结果是:Text1Tex2
public delegate String ProcessDelegate(String s1, String s2);
class Program
{
static void Main()
{
//使用委托ProcessDelegate来调用Process方法
ProcessDelegate pd = new ProcessDelegate(new Test().Process);
Console.WriteLine(pd("Text1", "Text2"));
}
}
public class Test
{
public String Process(String s1, String s2)
{
return s1 + s2;
}
}
2.回调函数
回调函数就是把一个方法传给另一个方法去执行。它与委托不同在于,它的方法参数,返回值都可以和调用者的参数,返回值可以不一样。
输出结果:
Text1Text2
Text1
Text2
Text2Text1
public delegate String ProcessDelegate(String s1, String s2);
class Program
{
static void Main()
{
Test t = new Test();
//Process方法(调用者)调用了一个回调函数Process1,当然这里只执行了回调函数。
//可以看出,可以把任意一个符合这个委托的方法传递进去,意思就是说这部分代码是可变的。
//将Process1 2 3方法传递给Process方法去执行
string r1 = t.Process("Text1", "Text2", new ProcessDelegate(t.Process1));
string r2 = t.Process("Text1", "Text2", new ProcessDelegate(t.Process2));
string r3 = t.Process("Text1", "Text2", new ProcessDelegate(t.Process3));
Console.WriteLine(r1);
Console.WriteLine(r2);
Console.WriteLine(r3);
}
}
public class Test
{
public String Process(String s1, String s2, ProcessDelegate process)
{
return process(s1, s2);
}
public String Process1(String s1, String s2)
{
return s1 + s2;
}
public String Process2(String s1, String s2)
{
return s1 + Environment.NewLine + s2;
}
public String Process3(String s1, String s2)
{
return s2 + s1;
}
}
17.1初识委托
以下代码演示了如何声明、创建和使用委托:
using System;
using System.Windows.Forms;
using System.IO;
namespace WindowsFormsApplication1
{
//声明一个委托类型,它的实例引用一个方法
//指定一个回调函数的签名,该方法获取一个Int32参数,返回void
internal delegate void Feedback(Int32 value);
public sealed class Program
{
public static void Main()
{
StaticDelegateDemo();
InstanceDelegateDemo();
ChainDelegateDemo1(new Program());
ChainDelegateDemo2(new Program());
}
public static void StaticDelegateDemo()
{
Console.WriteLine("----Static Delegate Demo----");
Counter(1, 3, null);
//前缀Program可选
Counter(1, 3, new Feedback(Program.FeedbackToConsole));
Counter(1, 3, new Feedback(FeedbackToMsgBox));
Console.WriteLine();
}
private static void InstanceDelegateDemo()
{
Console.WriteLine("----Instance Delegate Demo----");
Program p = new Program();
Counter(1, 3, new Feedback(p.FeedbackToFile));
Console.WriteLine();
}
private static void ChainDelegateDemo1(Program p)
{
Console.WriteLine("----Chain Delegate Demo 1----");
Feedback fb1 = new Feedback(FeedbackToConsole);
Feedback fb2 = new Feedback(FeedbackToMsgBox);
Feedback fb3 = new Feedback(p.FeedbackToFile);
Feedback fbChain = null;
fbChain = (Feedback)Delegate.Combine(fbChain, fb1);
fbChain = (Feedback)Delegate.Combine(fbChain, fb2);
fbChain = (Feedback)Delegate.Combine(fbChain, fb3);
Counter(1, 2, fbChain);
Console.WriteLine();
fbChain = (Feedback)Delegate.Remove(fbChain, new Feedback(FeedbackToMsgBox));
Counter(1, 2, fbChain);
}
private static void ChainDelegateDemo2(Program p)
{
Console.WriteLine("----Chain Delegate Demo 2----");
Feedback fb1 = new Feedback(FeedbackToConsole);
Feedback fb2 = new Feedback(FeedbackToMsgBox);
Feedback fb3 = new Feedback(p.FeedbackToFile);
Feedback fbChain = null;
fbChain += fb1;
fbChain += fb2;
fbChain += fb3;
Counter(1, 2, fbChain);
Console.WriteLine();
fbChain -= new Feedback(FeedbackToMsgBox);
Counter(1, 2, fbChain);
}
private static void Counter(Int32 from, Int32 to, Feedback fb)
{
for (Int32 val = from; val <= to; val++)
{
//如果指定了任何回调函数,就调用它们
if (fb != null)
fb(val);
}
}
private static void FeedbackToConsole(Int32 value)
{
Console.WriteLine("Item=" + value);
}
private static void FeedbackToMsgBox(Int32 value)
{
MessageBox.Show("Item=" + value);
}
private void FeedbackToFile(Int32 value)
{
StreamWriter sw = new StreamWriter("Status", true);
sw.WriteLine("Item=" + value);
sw.Close();
}
}
}
17.2用委托回调静态方法
在StaticDelegateDemo方法中,第一次调用Counter方法时,为第三个参数传递的是null。由于Counter的fb参数收到的是null,所以每个数据项在处理时,都不会调用回调函数。
接着StaticDelegateDemo方法再次调用Counter方法,为第三个参数传递一个新构造的Feedback委托对象。委托对象(new操作符新建的Feedback对象)是方法的一个包装器(wrapper),使方法能通过包装器来间接回调。
在本例中,静态方法的完整名称Program.FeedbackToConsole被传给Feedback委托类型的构造器。表明FeedbackToConsole就是要包装的方法。new操作符返回的引用作为Counter的第三个参数来传递。
在一个类型中,可以通过委托来调用另一个类型的私有成员时,只要委托对象是有具有足够安全性和可访问性的代码创建时,便不会有问题。
这个例子中的所有操作都是类型安全的。例如,在构造Feedback委托对象时,编译器确保Program的FeedbackToConsole方法的签名,兼容于Feedback委托定义的签名。具体的说,FeedbackToConsole必须获取一个参数,而且两者都必须有相同的返回类型(void)。
将一个方法绑定到委托时,C#和CLR都允许引用类型的协变形和逆变性。
17.3用委托回调实例方法
InstanceDelegateDemo中构造了一个名为p的Program对象。这个Program对象没有定义任何实例字段和属性。向Counter委托类型的构造函数传递的是p.FeedbackToFile,这导致委托包装对FeedbackToFile方法的一个引用,这个方法是实例方法,而不是静态方法。当Counter调用由其fb实参标识的回调函数时,会调用FeedbackToFile实例方法。
17.4委托揭秘
从表面看,委托似乎很容易使用:用C#的delegate关键字,用熟悉的new操作符构造委托实例。
CLR和编译器做了大量的工作来隐藏委托的复杂性。
以上是关于委托的主要内容,如果未能解决你的问题,请参考以下文章