学习c#都会惊奇于它的delegate,其实delegate并没有太多神秘的地方,说的通俗点,delegate是类型化了的函数指针,它主要应用于回调。
学习C的对函数指针都不回陌生,它是一个保存了函数地址的变量,但除了地址,它没有包含任何额外的信息,如参数的个数、参数类型和函数的返回地址等,所以函数指针是非类型安全的。而delegate对回调提供了类型的安全性,从而使我们在处理回调等问题的时候可以更加优美的面向对象的方式来编写代码,并且在CLR的内部对delegate的操作提供了许多支持(如delegate链表),简化了我们常用的操作。
在使用delegate的过程中,首先要定义一个delegate的类型
delegate result-type identifier ([parameters]);
where:
result-type: The result type, which matches the return type of the function.
identifier: The delegate name.
parameters: The Parameters, that the function takes.
Examples:
public delegate void SimpleDelegate ()
public delegate int ButtonClickHandler (object obj1, object obj2)
A very basic example (SimpleDelegate1.cs):
using System;
namespace Akadia.BasicDelegate
{
// Declaration
public delegate void SimpleDelegate();
class TestDelegate
{
public static void MyFunc()
{
Console.WriteLine("I was called by delegate ...");
}
public static void Main()
{
// Instantiation
SimpleDelegate simpleDelegate = new SimpleDelegate(MyFunc);
// Invocation
simpleDelegate();
}
}
}
Compile an test:
# csc SimpleDelegate1.cs
# SimpleDelegate1.exe
I was called by delegate ...
Calling Static Functions
using System;
namespace Akadia.SimpleDelegate
{
// Delegate Specification
public class MyClass
{
// Declare a delegate that takes a single string parameter
// and has no return type.
public delegate void LogHandler(string message);
// The use of the delegate is just like calling a function directly,
// though we need to add a check to see if the delegate is null
// (that is, not pointing to a function) before calling the function.
public void Process(LogHandler logHandler)
{
if (logHandler != null)
{
logHandler("Process() begin");
}
if (logHandler != null)
{
logHandler ("Process() end");
}
}
}
// Test Application to use the defined Delegate
public class TestApplication
{
// Static Function: To which is used in the Delegate. To call the Process()
// function, we need to declare a logging function: Logger() that matches
// the signature of the delegate.
static void Logger(string s)
{
Console.WriteLine(s);
}
static void Main(string[] args)
{
MyClass myClass = new MyClass();
// Crate an instance of the delegate, pointing to the logging function.
// This delegate will then be passed to the Process() function.
MyClass.LogHandler myLogger = new MyClass.LogHandler(Logger);
myClass.Process(myLogger);
}
}
}
Compile an test:
# csc SimpleDelegate2.cs
# SimpleDelegate2.exe
Process() begin
Process() end
Calling Member Functions
using System;
using System.IO;
namespace Akadia.SimpleDelegate
{
// Delegate Specification
public class MyClass
{
// Declare a delegate that takes a single string parameter
// and has no return type.
public delegate void LogHandler(string message);
// The use of the delegate is just like calling a function directly,
// though we need to add a check to see if the delegate is null
// (that is, not pointing to a function) before calling the function.
public void Process(LogHandler logHandler)
{
if (logHandler != null)
{
logHandler("Process() begin");
}
if (logHandler != null)
{
logHandler ("Process() end");
}
}
}
// The FileLogger class merely encapsulates the file I/O
public class FileLogger
{
FileStream fileStream;
StreamWriter streamWriter;
// Constructor
public FileLogger(string filename)
{
fileStream = new FileStream(filename, FileMode.Create);
streamWriter = new StreamWriter(fileStream);
}
// Member Function which is used in the Delegate
public void Logger(string s)
{
streamWriter.WriteLine(s);
}
public void Close()
{
streamWriter.Close();
fileStream.Close();
}
}
// Main() is modified so that the delegate points to the Logger()
// function on the fl instance of a FileLogger. When this delegate
// is invoked from Process(), the member function is called and
// the string is logged to the appropriate file.
public class TestApplication
{
static void Main(string[] args)
{
FileLogger fl = new FileLogger("process.log");
MyClass myClass = new MyClass();
// Crate an instance of the delegate, pointing to the Logger()
// function on the fl instance of a FileLogger.
MyClass.LogHandler myLogger = new MyClass.LogHandler(fl.Logger);
myClass.Process(myLogger);
fl.Close();
}
}
}
Compile an test:
# csc SimpleDelegate3.cs
# SimpleDelegate3.exe
# cat process.log
Process() begin
Process() end
Multicasting 【表示多重傳送的委派 (Delegate);也就是說,委派可以在它的引動過程清單中包含一個以上的項目】
using System;
using System.IO;
namespace Akadia.SimpleDelegate
{
// Delegate Specification
public class MyClass
{
// Declare a delegate that takes a single string parameter
// and has no return type.
public delegate void LogHandler(string message);
// The use of the delegate is just like calling a function directly,
// though we need to add a check to see if the delegate is null
// (that is, not pointing to a function) before calling the function.
public void Process(LogHandler logHandler)
{
if (logHandler != null)
{
logHandler("Process() begin");
}
if (logHandler != null)
{
logHandler ("Process() end");
}
}
}
// The FileLogger class merely encapsulates the file I/O
public class FileLogger
{
FileStream fileStream;
StreamWriter streamWriter;
// Constructor
public FileLogger(string filename)
{
fileStream = new FileStream(filename, FileMode.Create);
streamWriter = new StreamWriter(fileStream);
}
// Member Function which is used in the Delegate
public void Logger(string s)
{
streamWriter.WriteLine(s);
}
public void Close()
{
streamWriter.Close();
fileStream.Close();
}
}
// Test Application which calls both Delegates
public class TestApplication
{
// Static Function which is used in the Delegate
static void Logger(string s)
{
Console.WriteLine(s);
}
static void Main(string[] args)
{
FileLogger fl = new FileLogger("process.log");
MyClass myClass = new MyClass();
// Crate an instance of the delegates, pointing to the static
// Logger() function defined in the TestApplication class and
// then to member function on the fl instance of a FileLogger.
MyClass.LogHandler myLogger = null;
myLogger += new MyClass.LogHandler(Logger);
myLogger += new MyClass.LogHandler(fl.Logger);
myClass.Process(myLogger);
fl.Close();
}
}
}
Compile an test:
# csc SimpleDelegate4.cs
# SimpleDelegate4.exe
Process() begin
Process() end
# cat process.log
Process() begin
Process() end