为什么试图理解代表感觉想要了解宇宙的本质?

时间:2010-04-20 21:07:05

标签: c# delegates

我读了两本书,大量的例子。他们仍然对我毫无意义。我可能会写一些使用委托的代码,但我不知道为什么。我是唯一有这个问题的人,还是我只是个白痴?如果有人能真正向我解释我何时,何地以及为什么我会真正使用代表,我会永远爱你。

7 个答案:

答案 0 :(得分:17)

委托只是传递变量中函数的一种方法。

您传递委托函数来执行回调。例如,在执行异步IO时,您传递一个委托函数(您使用delegate参数编写的函数),该函数将在从磁盘读取数据时调用。

答案 1 :(得分:4)

正如其他人提到的那样,代表对回调很方便。它们对其他一些东西也很有用。例如,在我最近一直在努力的游戏中,子弹在击中时会做不同的事情(有些会造成伤害,有些实际上会增加他们击中的人的生命值,有些人没有受到伤害但会毒害目标等等)。执行此操作的经典OOP方法是基本项目类和子类加载

Bullet
    DamageBullet
    HealBullet
    PoisonBullet
    DoSomethingElseBullet
    PoisonAndThenHealBullet
    FooAndBarBullet
    ....

使用这种模式,每次我想要一个子弹中的一些新行为时,我必须定义一个新的子类,这是一个混乱并导致大量重复的代码。相反,我与代表解决了这个问题。子弹有一个OnHit委托,当子弹击中一个对象时调用它,当然我可以让那个委托给我喜欢的任何东西。所以现在我可以创建像这样的子弹

new Bullet(DamageDelegate)

这显然是一种更好的做事方式。

在函数式语言中,你往往会看到更多这类东西。

答案 2 :(得分:4)

Chris Sells的这篇文章可能有所帮助:

.NET Delegates: A C# Bedtime Story

答案 3 :(得分:3)

委托是一个简单的容器,它知道机器内存中特定方法的位置。

所有代表都有一个Invoke(...)方法,因此当有人拥有委托时,他实际上可以执行它,而不必真正了解或打扰该方法实际执行的操作。

这对于解耦东西特别有用。如果没有这个概念,GUI框架将无法实现,因为Button根本无法了解您将要使用它的程序,因此无论何时单击它都无法自行调用您的方法。相反,您必须告诉它在单击时应该调用哪些方法。

我猜你熟悉事件,你经常使用它们。 event字段实际上是此类委托的列表(也称为多播委托)。当我们看看如何在C#中“模拟”事件时,如果它没有event关键字,只有(非多播)委托,那么事情会变得更加清晰:

public class Button : Rectangle
{
    private List<Delegate> _delegatesToNotifyForClick = new List<Delegate>();

    public void PleaseNotifyMeWhenClicked(Delegate d)
    {
        this._delegatesToNotifyForClick.Add(d);
    }

    // ...

    protected void GuiEngineToldMeSomeoneClickedMouseButtonInsideOfMyRectangle()
    {
        foreach (Delegate d in this._delegatesToNotifyForClick)
        {
            d.Invoke(this, this._someArgument);
        }
    }
}

// Then use that button in your form

public class MyForm : Form
{
    public MyForm()
    {
        Button myButton = new Button();
        myButton.PleaseNotifyMeWhenClicked(new Delegate(this.ShowMessage));
    }

    private void ShowMessage()
    {
        MessageBox.Show("I know that the button was clicked! :))))");
    }
 }

希望我能帮助一点。 ; - )

答案 4 :(得分:2)

也许这会有所帮助:

  • 委托是一种类型(定义方法签名)
  • 委托实例是对方法(AKA函数指针)的引用
  • 回调是委托类型的参数
  • 事件是委托类型的(种类)属性

委托的目的是你可以拥有“保持”一个函数的变量/字段/参数/属性(事件)。这使您可以存储/传递选择运行时的特定函数。没有它,每个函数调用都必须在编译时修复。

涉及委托(或事件)的语法起初可能有点令人生畏,这有两个原因:

  1. 像C / C ++这样简单的函数指针不是类型安全的,在.NET中,编译器实际上会围绕它生成一个类,然后尝试尽可能地隐藏它。

  2. 代表是LINQ的基石,从C#1中的所有内容到匿名方法(C#2)到lambdas(C#3)都有一个陡峭的演变。

  3. 熟悉1或2种标准模式。

答案 5 :(得分:2)

来吧伙计们!所有人都成功地复制了代表:)!

我将尝试在这里留下一个提示:一旦我在Javascript中实现了jquery ajax调用,我理解了代理人。例如:ajax.send(url,data,successcallback,failcallback)是函数的签名。如您所知,它将数据作为响应发送到服务器URL,可能是200OK或其他一些错误。如果发生任何此类事件(成功/失败),您需要执行一个功能。因此,这就像一个函数的占位符,能够在成功或失败中提及。 该占位符可能不是非常通用 - 它可能接受一组参数并且可能/可能不会返回值。这个占位符的声明,如果在C#IS CALLED DELEGATE中完成!由于javascript函数对参数的数量不严格,你只能将它们视为GENERIC占位符......但是C#有一些STRICT声明......归结为DELEGATE声明!

希望它有所帮助!

答案 6 :(得分:0)

委托是类型安全函数指针,当调用委托函数 实际函数时,意味着委托指向函数将被调用。它主要用于开发核心应用程序框架。当我们想要解耦逻辑时,我们可以使用委托。也就是说,在特定方法中,我们可以将委托传递给函数,而在委托函数中设置不同的函数逻辑。代表们为您的框架增加了灵活性。

示例:如何使用

class program {
 public static void Main) {
  List<Employee> empList = new List<Employee> () {
   new Employee () {Name = "Test1", Experience = 6 },
   new Employee () {Name = "Test2", Experience = 2 },
  }

// delegate point to the actual function
IsPromotable isEligibleToPromote = new IsPromotable(IsEligibleToPromoteEmployee)
Employee emp = new Employee();

// pass the delegate to a method where the delegate will be invoked.
emp.PromoteEmployee(empList, isEligibleToPromote);

// same can be achieved using lambda empression no need to declare delegate 
emp.PromoteEmployee (empList, emply =>emply.Experience > 2);

   // this condition can change at calling end 
   public static bool IsEligibleToPromoteEmployee (emp){
      if (emp.Experience > 5)
       return true;
      else
      return false;
    }
  }
}


public delegate bool IsPromotable(Employee emp);

public class Employee  {
  public string Name {get; set;}
  public int Experience {get; set;}

  // conditions changes it can 5, 6 years to promote
  public void PromoteEmployee (List<Employee> employees, IsPromotable isEligibleToPromote) {
  foreach (var employee in employees) {
    // invoke actual function
    if (isEligibleToPromote(employee)){
       Console.WriteLine("Promoted");   
    }
  }
}