委托入门






4.39/5 (26投票s)
入门 - 关于委托的基础知识,如何定义和使用它们
引言
委托是一个概念,但不知为何它总是令人困惑。我每次想使用委托时,仍然需要搜索它来确保语法正确。让我们看看是否能将委托简化到更容易理解的程度。这是一篇入门文章,非常非常基础,甚至没有涉及到事件。有很多文章解释委托和事件,但我认为很多人在阅读这些文章时感到困惑,因为你需要先理解基础知识。这是我尝试解释基础知识的尝试,我希望这有帮助,因为这是一个难以解释的话题。
定义:委托“被指定代表他人或他人行事的人”
// Define a new type in the system called MathFunction
private delegate int MathFunction( int n1, int n2 );
// Create a variable of type MathFunction, the type MathFunction has been defined above.
private MathFunction adderFunction;
委托是一个保存函数的变量。就这么简单,我可以定义一个 `MathFunction` 类型的变量并将我的一个函数赋给它,然后稍后,而不是调用一个特定的函数,我可以使用该变量就像函数一样调用它,它将调用之前分配给它的函数。
声明变量时可以使用多种类型。`int`、`string` 和 `boolean` 是可以使用的一些原生类型。开发人员可以通过在代码中定义 `Classes`、`Delegates`、`Enums` 和 `Structs` 来定义自己的类型。上面我们定义了一个名为 `MathFunction` 的新 `Delegate Type`。我们现在可以在声明变量时使用此类型。在上面的代码示例中,我们创建了一个名为 `adderFunction` 的变量,它的类型是 `MathFunction`。`MathFunction` 类型是一个委托,这意味着它可以像函数一样使用,并在执行时代表某个函数调用它。回到委托的原始定义:“*一个用于代表函数的变量*”。
Using the Code
// Define a new type in the system called MathFunction
private delegate int MathFunction( int n1, int n2 );
// Declare a variable that will hold a function of type MathFunction.
private MathFunction adderFunction;
static void Main()
{
// Assign the real function Add() to the variable adderFunction
adderFunction = Add;
// Call whatever function has been stored in the variable adderFunction
int res = adderFunction( 1, 2 );
}
// This function matches exactly the signature defined in the MathFunction type
private int Add( int n1, int n2 )
{
return n1 + n2;
}
我们在系统中创建了一个名为 `MathFunction` 的新类型,并使用该类型声明了一个名为 `adderFunction` 的变量。此变量被赋值给 `Add` 函数。变量 `adderFunction` 可以像函数一样被调用 `adderFunction(5, 10);`,它将调用实际的 `Add` 函数。
函数可以有不同的返回类型、参数数量和参数类型。我们定义了 `MathFunction` 委托类型,以明确表示声明为该类型的变量可以像一个接受两个 `int` 参数并返回 `int` 类型的函数一样使用。现在我们已经定义了此变量可以持有的函数的签名(或原型),我们可以将一个完全匹配该签名的实际函数赋值给该变量。
实际应用示例
你是否曾写过一个函数,它做了一堆事情,然后做一些具体的事情,然后又做了一堆事情。现在将该函数复制粘贴 5 次,只改变中间的 3 或 4 行具体代码…… 如果你能将几行代码作为参数传递进去,然后有一个函数完成所有的开销,但在中间运行那 3 或 4 行具体代码,那不是很棒吗?这是委托的一个经典示例。
例如,当你与 Web 服务器通信时,在实际的 Web 调用之前和之后有很多开销,例如日志记录、计时、错误处理等。`MakeWebCall()` 函数实现了所有这些开销,但你需要运行 3 或 4 行具体代码来解析响应。是的,有其他方法可以做到这一点,无需委托... 不要为每个你需要发出的服务器调用类型复制粘贴此函数,而是通过向 `MakeWebCall` 函数添加一个委托参数来处理此问题。此委托接收 `HttpWebResponse` 对象,执行其特定的解析逻辑,然后返回一个 `string`(或者可能引发一个错误)。请看下面的代码。
private delegate string dgProcessResponse( HttpWebResponse response );
// ----------------------------------- Below we pass in the delegate function.
private string MakeWebCall( string url, dgProcessResponse ProcessResponseFunction )
{
string sResponse = String.Empty;
try
{
// Setup logging
// Setup Timing
// Setup Web Request object
// Call the Server
HttpWebRequest req = WebRequest.Create( url ) as HttpWebRequest;
HttpWebResponse response = req.GetResponse() as HttpWebResponse;
// Always check that your delegate isn't null!
if( ProcessResponseFunction != null )
{
sResponse = ProcessResponseFunction( response ); // <--- USE THE DELEGATE
}
}
catch( Exception ex )
{
// Handle errors
// Handle recoverable Logon Errors
}
finally
{
// End Timings
// End Logon
}
return sResponse;
}
关注点
- 有关委托的更多信息,请查看 A. Abdul Azeez 的这篇优秀文章。
委托和事件 - 未经审查的故事 - 第一部分 - 查看我的另一篇关于 BackgroundWorker 线程 的文章。
- 查看我的另一篇关于 虚拟 Treeviews 的文章。
- 查看我的另一篇关于 多选 Treeview 的文章。
Andrew D. Weiss
软件工程师
