如何在单独的文件中实现事件处理程序并使用依赖注入附加它?

Posted

技术标签:

【中文标题】如何在单独的文件中实现事件处理程序并使用依赖注入附加它?【英文标题】:How to implement event handler in a separate file and attach it by using dependency injection? 【发布时间】:2021-03-23 13:51:23 【问题描述】:

我正在使用 Discord.Net 创建 C# Discord 机器人。我的应用程序正在使用依赖注入,并且在 Program.cs 文件中我可以访问 DiscordSocketClient 的单例实例。

此实例提供许多事件,例如

discordSocketClient.UserJoined += async socketGuildUser =>

    // do things here
;

这似乎是一个与 C# 更相关的问题。我想创建单独的文件,每个文件都有一个事件处理程序,以保持代码井井有条。示例事件处理程序可能如下所示

public class UserJoinedHandler

    // Use the constructor to get access to services by using DI 

    public Task OnUserJoined(SocketGuildUser socketGuildUser)
    
        // Do things here
        
        return Task.CompletedTask;
    


附加此事件侦听器的最佳/最简单方法是什么?我想到的第一个解决方案是将此处理程序注册为单例服务

serviceCollection.AddSingleton<UserJoinedHandler>();

然后在我的 Program.cs 文件中我可以这样做

discordSocketClient.UserJoined += serviceProvider.GetService<UserJoinedHandler>().OnUserJoined;


是否有更好的解决方案来注册处理程序?例如。使用像[ThisClassHandlesTheUserJoinedEvent]这样的反射或注解,并让客户端通过添加像discordSocketClient.SearchForEventHandlingAnnotations()这样的扩展方法来搜索它们?

我知道这听起来像是过度工程,但这个项目很大,我喜欢有条理的代码。

【问题讨论】:

您设想什么样的可插拔架构需要这种复杂性? 将客户端注入处理程序并订阅事件。 我还不知道,但我只是希望有一种“最优化”的方式:) @Nikosi 但是我必须在某个地方注入所有这些处理程序来初始化它们,不是吗? 为处理程序创建一个通用接口,并有一个托管服务接收处理程序,以便它们可以在启动时初始化 【参考方案1】:

这更像是一半的答案/一半的评论。

注意不要过度使用依赖注入。它是一个很好的工具,可以帮助您避免代码中的紧密耦合,并使依赖服务的测试更容易,但它并不能帮助您组织代码。

在您的情况下,您实际上并没有依赖服务 - 即依赖于您的处理程序的服务。这意味着实际上没有任何东西可以注入它们。是的,您可以创建一个可以注入的包装类,该类收集并注册所有处理程序,但它真的为您增加了任何价值吗?

如果我是你,我只会有一个RegisterClientHandlers 的辅助类,然后为你的处理程序订阅那里的所有事件。如果您随后认为您需要能够测试处理程序的不同组合(比如UserJoinedHandler_v2UserLeftHandler_v1),那么您可以开始考虑使用通用处理程序接口将它们注入到帮助程序类中.

【讨论】:

以上是关于如何在单独的文件中实现事件处理程序并使用依赖注入附加它?的主要内容,如果未能解决你的问题,请参考以下文章

SpringBoot中实现依赖注入功能

如何使用依赖注入在 Xamarin.Forms 中实现 Flyoutnavigation

使用 Prism 在 Xamarin Forms 的后台服务中实现依赖注入

在 Python 中实现事件处理程序 [重复]

在旧版 Win32 应用程序中实现 COM 事件接收器

依赖注入在 dotnet core 中实现与使用:1 基本概念