在C# 中,委托类似于C++中的回调机制,声明一个委托类型,可以分别采用实例方法和静态方法实例化了委托,所不同的是采用静态方法实例化的委托,它的Target属性为null;而用实例方法实例化的委托,它的Target属性为该实例。但是这里要注意,如果你用Console.WriterLine(delegateObj.Target)输出该实例,结果是该实例的类型,而不是该实例的名字。
delegate String GetStatus();
Delegate[] arrayOfDelegates = status.GetInvocationList();
foreach (GetStatus getStatus in arrayOfDelegates)
{
try
{
report.AppendFormat("{0}{1}{1}",
getStatus(), Environment.NewLine);
}
catch (Exception e)
{
Object component = getStatus.Target;
report.AppendFormat( "Failed to get status from {1}{2}{0} Error: {3}{0}{0}",Environment.NewLine,
((component == null) ? "" : component.GetType() + "."),getStatus.Method.Name, e.Message);
}
}
class Mammals
{
public Mammals()
{
Console.WriteLine("Mammals");
}
}
class Dogs : Mammals
{
public Dogs()
{
Console.WriteLine("Dogs");
}
}
class Program
{
// Define the delegate.
public delegate Mammals HandlerMethod();
public static Mammals FirstHandler()
{
return new Mammals();
}
public static Dogs SecondHandler()
{
return new Dogs();
}
static void Main()
{
HandlerMethod handler1 = FirstHandler;
handler1();
Console.WriteLine();
// Covariance allows this delegate.
HandlerMethod handler2 = SecondHandler;
handler2();
Console.ReadLine();
}
}
输出结果为
Mammals
Mammals
Dogs
class Mammals
{
public Mammals()
{
Console.WriteLine("Mammals");
}
}
class Dogs : Mammals
{
public Dogs()
{
Console.WriteLine("Dogs");
}
}
class Program
{
public delegate void HandlerMethod(Dogs sampleDog);
public static void FirstHandler(Mammals elephant)
{
}
public static void SecondHandler(Dogs sheepDog)
{
}
static void Main(string[] args)
{
// Contravariance permits this delegate.
HandlerMethod handler1 = FirstHandler;
handler1(new Dogs());
Console.WriteLine();
HandlerMethod handler2 = SecondHandler;
handler2(new Dogs());
Console.ReadLine();
}
}
输出结果为:
Mammals
Dogs
Mammals
Dogs
目前我们所见到的委托都是通过一个命名方法来声明一个委托,在C#2.0以后就引入了匿名方法来声明一个委托,其创建方法很简单,就是把代码块作为委托的参数来声明即可,如下:其中d就是一个用匿名方法实例化的委托。
delegate void Del(int x);
Del d = delegate(int k) { /* ... */ };
这种委托的好处就是通过避免写一个方法来减少代码量,其最常见的一个应用就是创建线程。示例如下:
System.Threading.Thread t1 = new System.Threading.Thread
(delegate()
{
System.Console.Write("Hello, ");
System.Console.WriteLine("World!");
});
t1.Start();
但是匿名方法又很多限制,比如在其代码块不可以使用goto, break, continue等从代码块中跳到代码块外面,反之也是不可以的。
命名与匿名方法代码混合使用,代码示例:
delegate void Printer(string s);
class TestClass
{
static void Main()
{
Printer p = delegate(string j)
{
System.Console.WriteLine(j);
};
p("The delegate using the anonymous method is called.");
p = new Printer(TestClass.DoWork);
p("The delegate using the named method is called.");
}
static void DoWork(string k)
{
System.Console.WriteLine(k);
}
}
事件: 事件用于类或结构体通知对象来处理一些事情,事件是对delegate的应用,而且声明一个事件的时候,必须提供一个delegate类型,如下形式:
public delegate void SampleEventDelegate(object sender, EventArgs e);
public class SampleEventSource
{
public event SampleEventDelegate SampleEvent;
}
通过delegate,事件可以封装类型安全的方法,并在被触发的时候调用。声明了一个事件后,可以注册多个方法
到这个事件中,并且这些方法的参数类型、返回值,即signature必须一致。如在一个事件中同时注册里几个方
法,那么可以通过事件的GetInvocationList()方法来返回一个Delegate数组,通过遍历这个数组,就可以得到所有
回调函数(事件处理函数)的信息。事件的调用形式必须与其声明时的delegate的signature(签名)一致,如上
面声明的事件SampleEvent,在调用的时候必须如下形式调用SampleEvent(object,Systme.EventArgs.Empty)