我一直在努力理解C#中的委托,但似乎没有掌握使用它们的要点。下面是从MSDN关于委托的页面中稍微重构过的代码:
using System;
using System.Collections;
namespace Delegates
{
// Describes a book in the book list:
public struct Book
{
public string Title; // Title of the book.
public string Author; // Author of the book.
public decimal Price; // Price of the book.
public bool Paperback; // Is it paperback?
public Book(string title, string author, decimal price, bool paperBack)
{
Title = title;
Author = author;
Price = price;
Paperback = paperBack;
}
}
// Declare a delegate type for processing a book:
public delegate void ProcessBookDelegate(Book book);
// Maintains a book database.
public class BookDB
{
// List of all books in the database:
ArrayList list = new ArrayList();
// Add a book to the database:
public void AddBook(string title, string author, decimal price, bool paperBack)
{
list.Add(new Book(title, author, price, paperBack));
}
// Call a passed-in delegate on each paperback book to process it:
public void ProcessPaperbackBooksWithDelegate(ProcessBookDelegate processBook)
{
foreach (Book b in list)
{
if (b.Paperback)
processBook(b);
}
}
public void ProcessPaperbackBooksWithoutDelegate(Action<Book> action)
{
foreach (Book b in list)
{
if (b.Paperback)
action(b);
}
}
}
class Test
{
// Print the title of the book.
static void PrintTitle(Book b)
{
Console.WriteLine(" {0}", b.Title);
}
// Execution starts here.
static void Main()
{
BookDB bookDB = new BookDB();
AddBooks(bookDB);
Console.WriteLine("Paperback Book Titles Using Delegates:");
bookDB.ProcessPaperbackBooksWithDelegate(new ProcessBookDelegate(PrintTitle));
Console.WriteLine("Paperback Book Titles Without Delegates:");
bookDB.ProcessPaperbackBooksWithoutDelegate(PrintTitle);
}
// Initialize the book database with some test books:
static void AddBooks(BookDB bookDB)
{
bookDB.AddBook("The C Programming Language",
"Brian W. Kernighan and Dennis M. Ritchie", 19.95m, true);
bookDB.AddBook("The Unicode Standard 2.0",
"The Unicode Consortium", 39.95m, true);
bookDB.AddBook("The MS-DOS Encyclopedia",
"Ray Duncan", 129.95m, false);
bookDB.AddBook("Dogbert's Clues for the Clueless",
"Scott Adams", 12.00m, true);
}
}
}
如您在BookDB
类中所见,我定义了2种不同的方法:
- 一个接受委托作为参数:
ProcessPaperbackBooksWithDelegate
- 一个接受相应类型签名的操作作为参数:
ProcessPaperbackBooksWithoutDelegate
调用它们中的任何一个都会返回相同的结果,那么委托有什么用处呢?
同一页上的第二个示例会带来更多的困惑;以下是代码:
delegate void MyDelegate(string s);
static class MyClass
{
public static void Hello(string s)
{
Console.WriteLine(" Hello, {0}!", s);
}
public static void Goodbye(string s)
{
Console.WriteLine(" Goodbye, {0}!", s);
}
public static string HelloS(string s)
{
return string.Format("Hello, {0}!", s);
}
public static string GoodbyeS(string s)
{
return string.Format("Goodbye, {0}!", s);
}
public static void Main1()
{
MyDelegate a, b, c, d;
a = new MyDelegate(Hello);
b = new MyDelegate(Goodbye);
c = a + b;
d = c - a;
Console.WriteLine("Invoking delegate a:");
a("A");
Console.WriteLine("Invoking delegate b:");
b("B");
Console.WriteLine("Invoking delegate c:");
c("C");
Console.WriteLine("Invoking delegate d:");
d("D");
}
public static void Main2()
{
Action<string> a = Hello;
Action<string> b = Goodbye;
Action<string> c = a + b;
Action<string> d = c - a;
Console.WriteLine("Invoking delegate a:");
a("A");
Console.WriteLine("Invoking delegate b:");
b("B");
Console.WriteLine("Invoking delegate c:");
c("C");
Console.WriteLine("Invoking delegate d:");
d("D");
}
public static void Main3()
{
Func<string, string> a = HelloS;
Func<string, string> b = GoodbyeS;
Func<string, string> c = a + b;
Func<string, string> d = c - a;
Console.WriteLine("Invoking function a: " + a("A"));
Console.WriteLine("Invoking function b: " + b("B"));
Console.WriteLine("Invoking function c: " + c("C"));
Console.WriteLine("Invoking function d: " + d("D"));
}
}
Main1
是已经在示例中的函数。Main2
和Main3
是我添加的fiddles。
正如我所预料的那样,Main1
和Main2
给出了相同的结果:
Invoking delegate a:
Hello, A!
Invoking delegate b:
Goodbye, B!
Invoking delegate c:
Hello, C!
Goodbye, C!
Invoking delegate d:
Goodbye, D!
Main3
的结果非常奇怪:
Invoking function a: Hello, A!
Invoking function b: Goodbye, B!
Invoking function c: Goodbye, C!
Invoking function d: Goodbye, D!
如果 +
实际上执行的是函数组合,那么结果(对于 Main3
)应该是什么:Invoking function a: Hello, A!
Invoking function b: Goodbye, B!
Invoking function c: Hello, Goodbye, C!!
Invoking function d: //God knows what this should have been.
但很明显,+
实际上并不是传统的函数组合(对于动作(Action)而言,真正的组合甚至都行不通)。因为它似乎没有以下类型签名:
(T2 -> T3) -> (T1 -> T2) -> T1 -> T3
相反,类型签名似乎是:
(T1 -> T2) -> (T1 -> T2) -> (T1 -> T2)
那么+
和-
到底代表什么意思呢?
旁注:我试着在Main2
中使用var a = Hello;...
,但是出现了错误:
test.cs(136,14): error CS0815: Cannot assign method group to an implicitly-typed
local variable
可能与这个问题无关,但为什么不能这样做呢?这似乎是一种非常直接的类型推断。
Func
和Action
是.NET 3.5中添加的通用委托,作为一种方便的功能。 - Dustin Kingen