与代表有什么交易?

时间:2010-09-20 11:27:43

标签: c# asp.net vb.net

我理解委托封装了方法调用。但是我很难理解他们的需求。为什么要使用代表,他们设计的是什么情况?

8 个答案:

答案 0 :(得分:11)

委托基本上是方法指针。委托让我们创建一个引用变量,但它不是引用类的实例,而是引用类中的方法。它引用任何具有返回类型且具有与该委托指定的参数相同的参数的方法。这是一个非常有用的事件方面。为了全面阅读,我建议你阅读Head First C#中的主题(Andrew Stellman和Jennifer Greene)。它精美地解释了委托主题以及.NET中的大多数概念。

答案 1 :(得分:8)

嗯,一些常见用途:

  • 事件处理程序(在UI代码中很常见 - “单击按钮时,我希望此代码执行”)
  • 来自异步调用的回调
  • 为线程(或线程池)提供一个新任务来执行
  • 指定LINQ投影/条件等

不要将它们视为封装方法调用。将它们视为用特定签名封装一些任意位的行为/逻辑。 “方法”部分有点无关紧要。

另一种思考委托类型的方法是作为单方法接口。一个很好的例子是IComparer<T>接口及其双重Comparison<T>委托类型。它们代表了同样的基本理念;有时候,将它表达为委托更容易,有时候界面会让生活更轻松。 (当然,您可以轻松编写代码以在两者之间进行转换。)

答案 2 :(得分:5)

从广义上讲,它们的设计是因为当您拥有需要调用其他代码的代码时 - 但是您在编译时不知道其他代码可能是什么。

作为示例,请考虑使用委托的Windows窗体Button.Click事件。 Windows窗体程序员知道,当按下该按钮时,你会想要发生某些事情,但他们无法准确知道你想要做什么......它可能是任何东西!

因此,您创建一个方法并将其分配给委托并将其设置为该事件,而您就是这样。这是代表们的基本推理,尽管他们有很多其他相关的好用途。

答案 3 :(得分:4)

代表通常用于Events。根据MSDN,.NET中的代表是针对以下内容设计的:

  
      
  • 使用事件设计模式。
  •   
  • 希望封装静态方法。
  •   
  • 调用者无需访问其他属性,方法或接口   实现该方法的对象。
  •   
  • 需要简单的组合。
  •   
  • 一个类可能需要多个方法的实现方法
  •   

来自MSDN的另一个很好的解释,

  

使用a的一个很好的例子   单方法接口而不是   代表是IComparable或   IComparableIComparable宣布   CompareTo方法,返回一个   整数指定小于等于   到或超过关系   在两个相同类型的对象之间。   IComparable可以作为基础   排序算法,并使用   委托比较法作为   排序算法的基础是   有效,这并不理想。因为   比较能力属于   类和比较算法   在运行时不会改变,a   单方法接口是理想的。单方法接口是理想的。

自.NET 2.0起,它也被用于anonymous functions

维基百科对代表团模式有一个很好的解释,

  

在软件工程中,委托模式是面向对象编程中的设计模式,其中对象不是执行其声明的任务之一,而是将该任务委托给关联的辅助对象。它可以说是贬低(技术上讲,是一种责任倒置)。辅助对象称为委托。委托模式是构成其他软件模式的基本抽象模式之一,例如组合(也称为聚合),混合和方面。

答案 4 :(得分:1)

过度简化:我会说代理是一个函数的占位符,直到某个东西为代理分配一个真正的函数。调用未分配的代理会抛出异常。

发生混淆是因为定义,声明,实例化和委托的调用之间通常没有什么区别。

<强>定义:
像在任何类定义中一样,将它放在命名空间中。

public delegate bool DoSomething(string withThis);

这与类定义相当,因为您现在可以声明此委托的变量。

<强>声明:
这是函数例程之一,就像你声明任何变量一样。

DoSomething doSth;

实例化和作业:
通常你会和宣言一起做这件事。

doSth = new DoSomething(MyDoSomethingFunc);

“新的DoSomething(..)”是实例化。 doSth = ...是赋值。

请注意,您必须已经定义了一个名为“MyDoSomething”的函数,它接受一个字符串并返回一个bool。

然后你可以调用这个函数。

<强>调用:

bool result = doSth(myStringValue);

<强>活动:
您可以看到事件的来源:

由于班级成员通常是基于定义的声明 像

class MyClass {
    private int MyMember;
}

事件是基于代理人的声明:

public delegate bool DoSomething(string withWhat);

class MyClass {
    private event DoSomething MyEvent;
}

与前一个示例的不同之处在于事件是“特殊的”:

  1. 您可以在不抛出异常的情况下调用未分配的事件。
  2. 您可以为事件分配多个功能。然后它们将被顺序调用。如果其中一个调用抛出异常,则其余调用无法播放。
  3. 他们真的是代表阵列的语法糖。

    关键是当然/其他人会为你做分配。

答案 5 :(得分:0)

代理允许您传递对方法的引用。一个常见的例子是将compare方法传递给sort函数。

答案 6 :(得分:0)

如果您需要在运行时决定调用哪种方法,那么您可以使用委托。然后,委托将在运行时响应某个操作/事件,并调用适当的方法。就像把一个“代表”送到你不想参加的婚礼上一样: - )

C人会将此识别为函数指针,但不要在这里用术语表示。所有委托都做(并且它实际上是一个类型),提供方法的签名,稍后将调用该签名来实现适当的逻辑。

Dan Solis的“Illustrated C#”一书提供了学习这个概念的最简单的切入点:

http://www.amazon.com/Illustrated-2008-Windows-Net-Daniel-Solis/dp/1590599543

答案 7 :(得分:0)

委托通常是对象引用和指向对象的一个​​类方法的指针的组合(可以为静态方法创建委托,在这种情况下没有对象引用)。可以调用委托而不考虑包含对象的类型,因为包含的方法指针保证对包含的对象有效。

要理解代表背后的一些有用性,请回想一下语言C,以及C中函数的printf“系列”。假设有人想要一个不仅可以使用的“printf”的通用版本如printf,fprintf,sprintf等,但可以将其输出发送到串行端口,文本框,TCP端口,cookie结霜机器等,而无需预先分配缓冲区。显然,这样的函数需要接受字符输出例程的函数指针,但这本身通常是不够的。

典型的实现(遗憾的是没有标准化)将有一个通用的gp_printf例程,它接受(除了格式字符串和输出参数)一个void指针,以及一个指向接受一个字符和一个void指针的函数的指针。 gp_printf例程不会将传入的void指针用于任何目的,而是将其传递给字符输出函数。然后该函数可以将指针转换为FILE *(如果gp_printf由fprintf调用),或者char **(如果它被sprintf调用),或者SERIAL_PORT *(如果它被serial_printf调用),或者其他什么

请注意,因为任何类型的信息都可以通过void *传递,所以gp_printf可以做什么没有限制。然而,存在一种危险:如果在void *中传递的信息不是函数所期望的,则可能导致未定义的行为(即可能是非常糟糕的事情)。调用者有责任确保函数指针和void *正确配对;系统中没有任何东西可以防止错误使用。

在.net中,委托将提供上面的函数指针和void *的组合功能,并且委托的构造函数将确保数据具有该函数的正确类型。一个方便的功能。