为什么我们要使用事件关键字,尽管应用程序可以在没有它的情况下工作?

Why should we use event keyword though the app works without it?

提问人:Soner from The Ottoman Empire 提问时间:3/31/2023 最后编辑:Peter CsalaSoner from The Ottoman Empire 更新时间:3/31/2023 访问量:53

问:

我仍然难以理解使用事件关键字与不实际之间的区别。例如,如果我们删除以下示例中的关键字,则一切正常。如果它有效,我们为什么需要它?我仍然可以制作一些供订阅者消费的东西。如果有必要知道的话,我正在研究 .Net 6。event

using System;
using System.Threading;

public class Order
{
    public string Item { get; set; }
    public string Ingredients { get; set; }
}

public class FoodOrderingService
{
    public delegate void FoodPreparedEventHandler(object source, EventArgs args);
    public event FoodPreparedEventHandler FoodPrepared;

    public void PrepareOrder(Order order)
    {
        Console.WriteLine($"Preparing your order '{order.Item}', please wait...");
        Thread.Sleep(4000);

        OnFoodPrepared();
    }

    protected virtual void OnFoodPrepared()
    {
        FoodPrepared?.Invoke(this, null);
    }
}

public class AppService
{
    public void OnFoodPrepared(object source, EventArgs eventArgs)
    {
        Console.WriteLine("AppService: your food is prepared.");
    }
}

class Program
{
    static void Main(string[] args)
    {
        var order = new Order { Item = "Pizza with extra cheese" };

        var orderingService = new FoodOrderingService();
        var appService = new AppService();
        //var mailService = new MailService();

        orderingService.FoodPrepared += appService.OnFoodPrepared;
        //orderingService.FoodPrepared += mailService.OnFoodPrepared;

        orderingService.PrepareOrder(order);

        Console.ReadKey();
    }
}
C# 事件 委托

评论

0赞 ProgrammingLlama 3/31/2023
除了 jmcilhinney 的回答之外,明确一点是件好事。
0赞 Soner from The Ottoman Empire 3/31/2023
@ProgrammingLlama但为什么在这种情况下(: ?

答:

2赞 jmcilhinney 3/31/2023 #1

如果删除该代码中的关键字,则只剩下以下内容:event

public FoodPreparedEventHandler FoodPrepared;

因此,这是一个公共字段,其行为与任何其他字段一样。是的,您仍然可以从类中调用委托,但您不仅限于此,就像处理事件一样。这是来自关键字的文档,您应该已经阅读过:event

事件是一种特殊的多播委托,只能是 从类(或派生类)或结构中调用,其中 它们被声明(Publisher 类)。如果其他类或结构 订阅事件,其事件处理程序方法将被调用 当 Publisher 类引发事件时。

如果它是一个字段,则可以从任何可以访问它的位置替换任何现有委托,也可以从外部调用这些现有委托。对于事件,您不能执行任何操作。

评论

0赞 Soner from The Ottoman Empire 3/31/2023
你是否介意用一个最小的代码示例来显示根据你说你可以从任何可以访问它的地方替换任何现有的委托,你也可以从外部调用这些现有的委托。对于事件,您不能执行任何操作。?
1赞 jmcilhinney 3/31/2023
@SonerfromTheOttomanEmpire,为什么你需要我举例说明公共领域是如何运作的?您已经知道如何获取或设置字段。类型与此没有区别。
0赞 Soner from The Ottoman Empire 3/31/2023
因为在我看来,你太有经验的人了,即使你按一下键,我也可能会学到新东西,所以我不想错过这个机会(:
0赞 jmcilhinney 3/31/2023
@SonerfromTheOttomanEmpire,没有什么可学的。字段是字段,字段是字段。如果字段是公共的,那么您可以获取它引用的对象并使用它,无论它是什么类型。如果类型是委托,则可以获取该对象并使用它。这是一个与其他任何领域一样的领域。你知道一个领域是如何运作的。不要再试图让它比实际情况更复杂了。
0赞 Soner from The Ottoman Empire 3/31/2023
好的,先生,你怎么想。谢谢你的帮助。
1赞 Peter Csala 3/31/2023 #2

请允许我试着强调其中的一些差异。

为了简单起见,让我们有这样的代码:

public delegate void FoodPreparedEventHandler(object source, EventArgs args);
public class FoodOrderingService 
{
   public event FoodPreparedEventHandler FoodPreparedEvent;
   public FoodPreparedEventHandler FoodPrepared;
}
var service = new FoodOrderingService();

//DOES COMPILE
service.FoodPrepared = new FoodPreparedEventHandler((_, ___) => {});
service.FoodPrepared(null, null);

//DOES NOT COMPILE
service.FoodPreparedEventHandler = new FoodPreparedEventHandler((_, ___) => {}); 
service.FoodPreparedEvent(null, null);
  • 无法重新分配(只能使用或运算符)event-=+=
  • 不能在类外部调用event

+1 在接口中,您不能定义字段,但可以定义事件

public interface IFoodOrderingService
{
   event FoodPreparedEventHandler FoodPreparedEvent;
   FoodPreparedEventHandler FoodPrepared; //DOES NOT COMPILE
}

Dotnet 小提琴链接

评论

0赞 Soner from The Ottoman Empire 3/31/2023
谢谢。+1,然而,“覆盖”关键字有点令人困惑。相反,“重新分配”会更好。
0赞 Peter Csala 3/31/2023
@SonerfromTheOttomanEmpire True,更正:D