我应该如何以及为什么要使用事件和委托

How and why should I use Events and delegates

我阅读了有关事件和代表的信息。我想我明白它们是如何工作的,但我不明白为什么要使用它们。

例如,我有一个网上商店,客户有余额并正在使用这笔钱购买产品。

这足以完成这项工作。 当用户买东西、卖东西或存钱时 - 调用 UserWallet class。

class Shop
{
    public static void BuyOrderFilled(){
        if(userHasBalance()){
            UserWallet userWallet = new UserWallet();
            userWallet.DeductMoney();
        }

        UpdateInventory();
    }

    public static void SellOrderFilled(){
        //Sell order has different logic
        if(userHasProduct()){
            UserWallet userWallet = new UserWallet();
            userWallet.RemoveProductFromUser();
        }

        UpdateInventory();
    }
}

class Deposit{
    public static void UserGotDeposit(decimal amount){
        UserWallet userWallet = new UserWallet();
        userWallet.FillUserBalance(amount);
    }
}

class UserWallet{
    public void DeductMoney(){
        //Some logic
    }
    public void RemoveProductFromUser(){
        //Some logic
    }
    public void FillUserBalance(){
        //Some logic
    }
}
public class Main(){
    Shop.BuyOrderFilled();
    Shop.SellOrderFilled();
    Deposit.UserGotDeposit(100);
}

既然我可以在需要时调用 UserWallet 方法,为什么还要使用事件或委托?

您不必使用它们..

..只是有时候能够像传递数据一样传递方法非常方便。

如果您正在提供一个库供其他人使用并且您想让它对他们有用但您对他们的代码或他们将如何使用一无所知它。一个明显的是框架中的List<T>;您可能正在编写类似的东西,并希望为人们提供一种搜索 if 的方式,但您不知道他们会将哪种对象放入列表中或他们希望如何搜索它们。

但是,如果您只是向他们提供类似 Find(delegate) 的方法,那么它就是一个“将方法作为参数的方法”——您向用户声明“为 Find 提供一个采用 T 的方法并且 return 是一个布尔值 true 如果它应该包含在搜索结果中”,那么这意味着他们可以编写这样的方法:

bool IsSmith(Person p) {
  return p.LastName == "Smith";
}

他们可以将它传递给您的列表 Find 方法,您的方法 运行 是他们的方法,给它 List 对象,得到一个 bool 并根据结果决定做什么

var smiths = myListOfPeople.Find(IsSmith);

现在我们通常不会手写这么长的方法,我们使用时髦的内联声明,我们只提供参数名称和逻辑,编译器插入它可以解决的所有其他内容

var smiths = myListOfPeople.Find(p => p.LastName == "Smith");

本质上,您可以在编写 List class 时控制过程的每个部分,您可以执行查找,可以 return 结果 - 但要使您的 List 真正灵活且让人们在其中存储他们想要的东西,您会在中间创建一个缺口,您无法知道如何搜索用户放入其中的任何内容。能够让他们在(已知参数类型和 return 类型)中传递一个您可以调用的方法,从而缩小差距


另一个例子;这次的事件,但他们没有什么不同。一个事件只是一个方法列表,您的 class 的用户可以用“发生某些事情时应该 运行 的代码位”填充这些方法

点击一个按钮:你想下载一个文件,你的同事想保存一张图片,我想计算文本框中输入的数字的因数。我们都在使用同一个按钮 class 但是当我们点击不同的按钮时,我们都想做不同的事情,所以微软制作完美按钮的最简单方法就是留下“点击时执行此操作”部分让我们填写,这样就完成了通过一种方法将委托(像变量一样传递的方法)与按钮相关联,并对按钮进行编码,以便在单击时 运行 成为委托,无论委托可能做什么


所有这一切对 Microsoft 来说都是很棒的,他们创建了按钮和列表以及其他通用的东西供我们享受,但它在我们自己的代码中是否有一席之地?当然,虽然比较少见,但我发现制作一些帮助程序 class 会很有帮助,例如 - 启动 ffmpeg 并从其输出流中读取的东西.. 大多数情况下它只是胡说八道,但偶尔会发送有趣的消息,所以我可能会制作发送此类消息时我引发的事件。我在一个项目中使用我的助手,我正在寻找丢帧,在另一个项目中我想知道是否检测到静音。在那些情况下,我认为“那个人向使用图书馆的人提供图书馆”是我的两端。我有其他项目,我想在不同的数据上执行类似的任务,编写器例程相同但解析不同;能够通过一种方法来说明如何从这个对象中提取一个名字,但是从那个对象中提取一个数字,这比拥有一些巨大的“如果对象是人则提取名称,否则如果对象是建筑物则提取”要好得多号码和街道”条件块在它不属于的地方