委托听名字感觉蛮有意思,大概意思是把事情托付给他人完成。
1 委托的基本介绍
委托的由来也许是 C++中的函数指针,但它具有函数指针的类型的功能,使用委托实例调用方法。委托是一种类型,用来定义函数的签名(返回值在这里作为签名的一部分)。由此,不妨这样理解,定义了某种委托,该委托确定了方法的签名,如下所示。
public delegate void MyString(string s);
使用delegate关键词定义了MyString委托,该委托访问权限为 public,其确定的方法的返回类型为空,接收一个字符串参数。
然后将该委托实例化为对象,而对象是需要初始化的,由此则将与由委托确定的方法相同签名的方法赋值给该委托,如下所示。
定义了两个域委托定义一致的方法。
public static void Myfuction1(string s)
{
Console.WriteLine("f1:" + s);
}
public static void Myfuction2(string s)
{
Console.WriteLine("f2:" + s);
}
接着实例化委托,并赋值。
MyString MS1 = new MyString(Myfuction1);
MyString MS2 = Myfuction2;
在 .net早期版本中,支持的是第一种方式,在后面的版本中,可以直接使用方法对委托实例对象进行“赋值”。
接下来就可以使用对象去调用被赋值的方法。
MS1("ni hao!");
MS2("ni hao!");
输出结果如下。
f1: ni hao!
f2: ni hao!
至此,可以知道委托是对方法的引用的类型,可以使用具体方法对其进行实例化,可以使用委托对象调用方法。
2 委托的特性
委托是一种安全地封装方法的类型,它与 C和 C++中的函数指针类似。与 C中的函数指针不同,委托是面向对象的、类型安全的和保险的。
构造委托对象时,通常是使用命名的方法对其进行封装,但也可以使用匿名方法和 Lambda表达式对其进行封装。
委托类型派生自 .NETFramework中的 Delegate类。委托类型是密封的,不能从 Delegate中派生委托类型,也不可能从中派生自定义类。
由于实例化委托是一个对象,所以可以将其作为参数进行传递,也可以将其赋值给属性。
由于委托不需要直接调用控制台,仅只是准备字符串并将字符串传递给其它方法,所以,委托的方法可以使用任意数量的参数。
委托不仅可以引用实例方法,而且可以引用静态方法。当引用实例方法时,将同时引用实例和方法,当引用静态方法时,只引用方法。
3 委托的简单应用
在下面的实例中定义了书本结构,接着定义了处理书本的委托,定义了书店类,在书店类中定义了方法,并将委托作为方法参数传递给方法,并在方法中调用委托。然后,分别定义了实例方法和静态方法用以处理书本,在类 program中实例化对象,并将方法“赋值”给委托,当调用方法时,便完成了相应书本的处理。
namespace 小书店
{
public struct Book
{
public string Title; // Title of the book.
public decimal Price; // Price of the book.
public Book(string title, decimal price)
{
Title = title;
Price = price;
}
}
// Declare a delegate type for processing a book:
public delegate void ProcessBookDelegate(Book book);
public class BookStore
{
Book book = new Book("The C Programming Language", 19.95m);
public void ProcessBooks(ProcessBookDelegate processBook)
{
processBook(book);
}
}
class ConsiderPericIsReasonable
{
public void judge(Book b)
{
if (b.Price > 20)
{
Console.WriteLine("unreasonable");
}
else
{
Console.WriteLine("reasonable");
}
}
}
class Program
{
static void PrintTitle(Book b)
{
System.Console.WriteLine("{0}", b.Title);
}
static void Main(string[] args)
{
BookStore bookDB = new BookStore();
bookDB.ProcessBooks(PrintTitle); //静态成员方法的初始化委托
ConsiderPericIsReasonable consider = new ConsiderPericIsReasonable();
bookDB.ProcessBooks(consider.judge); //实例成员方法的初始化委托
}
}
}
输出结果为。
The CProgramming Language
reasonable
委托的使用使得数据端与客户端之间功能良好的分离,在设计数据时不必考虑客户端对数据的具体处理现实,而客户端同样不需考虑数据具体存取形式。就如上程序,书店类仅只定义了书本处理程序标准,并没有定义具体的实现;打印书本标题、考虑价格是否合理也不需考虑,书店类中书本的存取形式及实现细节。
3 合并委托(多播委托)
在前面的示例中,一个委托实例对应一个方法,如果将多个方法分配给一个委托实例时,则形成多播委托。
对多播委托可以使用 +、+=或者 -、-=将方法(或者相同类型的委托实例)添加到委托实例上或从委托实例上移除,当调用多播委托是,会按照添加的顺序调用列表中的方法。
示例如下(摘取C#编程指南)。
// Define two methods that have the same signature as CustomDel.
static void Hello(string s)
{
System.Console.WriteLine(" Hello, {0}!", s);
}
static void Goodbye(string s)
{
System.Console.WriteLine(" Goodbye, {0}!", s);
}
static void Main()
{
// Declare instances of the custom delegate.
CustomDel hiDel, byeDel, multiDel, multiMinusHiDel;
// In this example, you can omit the custom delegate if you
// want to and use Action<string> instead.
//Action<string> hiDel, byeDel, multiDel, multiMinusHiDel;
// Create the delegate object hiDel that references the
// method Hello.
hiDel = Hello;
// Create the delegate object byeDel that references the
// method Goodbye.
byeDel = Goodbye;
// The two delegates, hiDel and byeDel, are combined to
// form multiDel.
multiDel = hiDel + byeDel;
// Remove hiDel from the multicast delegate, leaving byeDel,
// which calls only the method Goodbye.
multiMinusHiDel = multiDel - hiDel;
Console.WriteLine("Invoking delegate hiDel:");
hiDel("A");
Console.WriteLine("Invoking delegate byeDel:");
byeDel("B");
Console.WriteLine("Invoking delegate multiDel:");
multiDel("C");
Console.WriteLine("Invoking delegate multiMinusHiDel:");
multiMinusHiDel("D");
}
}
输出如下。
Invoking delegate hiDel:
Hello, A!
Invoking delegate byeDel:
Goodbye, B!
Invoking delegate multiDel:
Hello, C!
Goodbye, C!
Invoking delegate multiMinusHiDel:
Goodbye, D!
4 委托的高级应用——事件
这一部分将在下一篇中详细陈述。
5 参考
C#编程指南
C#自学手册