我一直在尝试了解 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
是我添加的小提琴。
正如我所料,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!
如果+
实际上是在执行函数组合,那么结果(for 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.
但很明显,这+
实际上并不是传统的函数式组合(我猜,真正的组合甚至不适用于动作)。从它似乎没有类型签名的事实可以看出这一点:
(T2 -> T3) -> (T1 -> T2) -> T1 -> T3
相反,类型签名似乎是:
(T1 -> T2) -> (T1 -> T2) -> (T1 -> T2)
那么到底是什么+
意思-
呢?
旁白:我尝试使用var a = Hello;...
inMain2
但出现错误:
test.cs(136,14): error CS0815: Cannot assign method group to an implicitly-typed
local variable
它可能与这个问题无关,但为什么不能这样做呢?这似乎是一个非常直接的类型扣除。