获取.NET Core中实现接口并调用函数的所有类

Mar*_*dru 1 c# reflection .net-core

如果特定类的字符串成员与给定的字符串成员匹配,如何获取实现特定接口的所有类,然后调用该类的函数?

\n

基本上我拥有的是一个ICommandHandler界面:

\n
interface ICommandHandler\n{\n    string Command { get; }\n    Task ExecuteAsync();\n}\n
Run Code Online (Sandbox Code Playgroud)\n

以及一个实现它的类:

\n
public class StartCommand : ICommandHandler\n{\n\n    public string Command { get => "start"; }\n    public async Task ExecuteAsync()\n    {\n      // do something\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n

我想要做的是获取所有实现 ICommandHandler 接口的类,然后验证是否class.Command等于特定字符串,如果等于则调用该ExecuteAsync方法。

\n

我尝试在这里使用这个答案: https: //stackoverflow.com/a/45382386/15306888class.Command总是null

\n

编辑:我得到的答案做了我想做的事情:

\n

我正在寻找一种使用 ICommandHandler 的方法,让我可以轻松收集从它继承的所有类并调用该函数,ExecuteAsync而不必在处理 TdLib 消息事件的代码部分中手动添加方法。

\n

所以现在我的项目目录看起来像这样:

\n
    \n
  • TelegramClient.cs- 加载从 ICommandHandler 继承的类的位置,ExecuteAsync如果 Command 成员与从电报返回的消息中解析的 Command 匹配,则调用该方法。
  • \n
  • Handlers/- 我的处理程序的基本目录\n
      \n
    • CommandHandlers/- 包含ICommandHandler接口和继承自它的类的文件夹
    • \n
    • MessageHandlers/- 具有另一个接口IMessageHandler和继承自它的类的文件夹
    • \n
    \n
  • \n
\n

不管怎样,与此同时,我在 stackoverflow 问题上找到了另一个答案(必须滚动几次),这使得获取多个处理程序变得更容易、更快,而不必一遍又一遍地重复相同的代码。我最后将上面链接的答案与这个答案结合起来:/sf/answers/2915504021/

\n

所以我用一个简单的方法结束了:

\n
        public static IEnumerable<T> GetAll<T>()\n        {\n            return Assembly.GetExecutingAssembly()\n                .GetTypes()\n                .Where(type => typeof(T).IsAssignableFrom(type))\n                .Where(type =>\n                    !type.IsAbstract &&\n                    !type.IsGenericType &&\n                    type.GetConstructor(new Type[0]) != null)\n                .Select(type => (T)Activator.CreateInstance(type))\n                .ToList();\n        }\n
Run Code Online (Sandbox Code Playgroud)\n

可以很容易地使用它,例如:

\n
      private async Task ProcessMessage(TdApi.Update.UpdateNewMessage message)\n        {\n            var command = GetCommand(message.Message);\n            var textMessage = GetMessageText(message.Message);\n\n            if (!String.IsNullOrWhiteSpace(command))\n            {\n                var commandHandlers = GetAll<ICommandHandler>();\n\n                foreach (var handler in commandHandlers)\n                {\n                    if (command == handler.Command)\n                        await handler.ExecuteAsync(_client, message.Message);\n                }\n            }\n\n            else if (!String.IsNullOrWhiteSpace(textMessage))\n            {\n                var messageHandlers = GetAll<IMessageHandler>();\n                foreach (var handler in messageHandlers)\n                {\n                    var outgoing = handler.Outgoing && message.Message.IsOutgoing;\n                    var incoming = handler.Incoming && !message.Message.IsOutgoing;\n\n                    if (outgoing || incoming)\n                    {\n                        if (!String.IsNullOrEmpty(handler.Pattern))\n                        {\n                            var match = Regex.Match(textMessage, handler.Pattern);\n                            if (match.Success)\n                                await handler.ExecuteAsync(_client, message.Message);\n                        }\n                    }\n                }\n            }\n        }\n
Run Code Online (Sandbox Code Playgroud)\n

接口的实际实现方式:

\n
using System;\nusing System.Collections.Generic;\nusing System.Text;\nusing System.Threading.Tasks;\nusing TdLib;\n\nnamespace YoutubeDl_Bot.Handlers.CommandHandlers\n{\n    public class StartCommand : ICommandHandler\n    {\n        public string Command { get => "/start"; }\n\n        public async Task ExecuteAsync(TdClient client, TdApi.Message message)\n        {\n            var stringBuilder = new StringBuilder();\n            stringBuilder.AppendLine("Hi! I\'m a bot that downloads and sends video and audio files from youtube links and many other supported services");\n            stringBuilder.AppendLine(String.Empty);\n            stringBuilder.AppendLine("**Usage:**");\n            stringBuilder.AppendLine("\xe2\x80\xa2 Send or forward a text message containing links and I will:");\n            stringBuilder.AppendLine("\xe2\x80\xa2 Download the best audio quality available for the video in the speecified link");\n            stringBuilder.AppendLine("\xe2\x80\xa2 Download the best video quality available for the video in the speecified link");\n            stringBuilder.AppendLine("\xe2\x80\xa2 Send the direct download URL for every link specified in the message");\n            stringBuilder.AppendLine("\xe2\x80\xa2 Supported links are available here: https://ytdl-org.github.io/youtube-dl/supportedsites.html");\n\n            var formattedText = await client.ExecuteAsync(new TdLib.TdApi.ParseTextEntities { Text = stringBuilder.ToString(), ParseMode = new TdLib.TdApi.TextParseMode.TextParseModeMarkdown() });\n            await client.ExecuteAsync(new TdLib.TdApi.SendMessage { ChatId = message.ChatId, InputMessageContent = new TdLib.TdApi.InputMessageContent.InputMessageText { Text = formattedText } });\n        }\n    }\n}\n\n
Run Code Online (Sandbox Code Playgroud)\n

完整的 TelegramClient 类:

\n
using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Reflection;\nusing System.Text.RegularExpressions;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing TdLib;\nusing YoutubeDl_Bot.Handlers.CallbackHandlers;\nusing YoutubeDl_Bot.Handlers.CommandHandlers;\nusing YoutubeDl_Bot.Handlers.MessageHandlers;\nusing YoutubeDl_Bot.Settings;\nusing YoutubeDl_Bot.Utils;\n\nnamespace YoutubeDl_Bot\n{\n    class TelegramBotClient\n    {\n        private static TdClient _client;\n        private static TdLib.TdApi.User _me;\n\n        private static int _apiId;\n        private static string _apiHash;\n        private static string _token;\n\n#if DEBUG\n        private static readonly int _verbosityLevel = 4;\n#else\n        private static readonly int _verbosityLevel = 0; \n#endif\n\n        public static bool AuthCompleted = false;\n\n        public TelegramBotClient(int apiId, string apiHash)\n        {\n            _apiId = apiId;\n            _apiHash = apiHash;\n        }\n\n        public async Task<TdClient> CreateClient()\n        {\n            _client = new TdClient();\n            await _client.ExecuteAsync(new TdApi.SetLogVerbosityLevel { NewVerbosityLevel = _verbosityLevel });\n            return _client;\n        }\n\n        public void StartListening(string botToken)\n        {\n            _token = botToken;\n            _client.UpdateReceived += _client_UpdateReceived;\n        }\n\n        private async void _client_UpdateReceived(object sender, TdApi.Update update)\n        {\n            switch (update)\n            {\n                case TdApi.Update.UpdateAuthorizationState updateAuthorizationState when updateAuthorizationState.AuthorizationState.GetType() == typeof(TdApi.AuthorizationState.AuthorizationStateWaitTdlibParameters):\n                    await _client.ExecuteAsync(new TdApi.SetTdlibParameters \n                    {\n                        Parameters = new TdApi.TdlibParameters\n                        {\n                            ApiId = _apiId,\n                            ApiHash = _apiHash,\n                            ApplicationVersion = "0.0.1",\n                            DeviceModel = "Bot",\n                            SystemLanguageCode = "en",\n                            SystemVersion = "Unknown"\n                        }\n                    });\n                    break;\n                case TdApi.Update.UpdateAuthorizationState updateAuthorizationState when updateAuthorizationState.AuthorizationState.GetType() == typeof(TdLib.TdApi.AuthorizationState.AuthorizationStateWaitEncryptionKey):\n                    await _client.ExecuteAsync(new TdLib.TdApi.CheckDatabaseEncryptionKey());\n                    break;\n                case TdLib.TdApi.Update.UpdateAuthorizationState updateAuthorizationState when updateAuthorizationState.AuthorizationState.GetType() == typeof(TdLib.TdApi.AuthorizationState.AuthorizationStateWaitPhoneNumber):\n                    await _client.ExecuteAsync(new TdLib.TdApi.CheckAuthenticationBotToken { Token = _token });\n                    break;\n                case TdLib.TdApi.Update.UpdateConnectionState updateConnectionState when updateConnectionState.State.GetType() == typeof(TdLib.TdApi.ConnectionState.ConnectionStateReady):\n                    // To Do Settings\n                    var botSettings = new BotSettings(_apiId, _apiHash, _token);\n                    _me = await _client.ExecuteAsync(new TdLib.TdApi.GetMe());\n                    Helpers.Print($"Logged in as: {_me.FirstName}");\n\n                    SettingsManager.Set<BotSettings>("BotSettings.data", botSettings);\n                    break;\n                case TdLib.TdApi.Update.UpdateNewMessage message:\n                    if (!message.Message.IsOutgoing)\n                        await ProcessMessage(message);\n                    break;\n                case TdApi.Update.UpdateNewCallbackQuery callbackQuery:\n                    await ProcessCallbackQuery(callbackQuery);\n                    break;\n                default:\n                    break;\n            }\n        }\n\n        #region PROCESS_MESSAGE\n        private async Task ProcessMessage(TdApi.Update.UpdateNewMessage message)\n        {\n            var command = GetCommand(message.Message);\n            var textMessage = GetMessageText(message.Message);\n\n            #region COMMAND_HANDLERS\n\n            if (!String.IsNullOrWhiteSpace(command))\n            {\n                var commandHandlers = GetAll<ICommandHandler>();\n\n                foreach (var handler in commandHandlers)\n                {\n                    if (command == handler.Command)\n                        await handler.ExecuteAsync(_client, message.Message);\n                }\n            }\n\n            #endregion\n\n            #region MESSAGE_HANDLERS\n\n            else if (!String.IsNullOrWhiteSpace(textMessage))\n            {\n                var messageHandlers = GetAll<IMessageHandler>();\n                foreach (var handler in messageHandlers)\n                {\n                    var outgoing = handler.Outgoing && message.Message.IsOutgoing;\n                    var incoming = handler.Incoming && !message.Message.IsOutgoing;\n\n                    if (outgoing || incoming)\n                    {\n                        if (!String.IsNullOrEmpty(handler.Pattern))\n                        {\n                            var match = Regex.Match(textMessage, handler.Pattern);\n                            if (match.Success)\n                                await handler.ExecuteAsync(_client, message.Message);\n                        }\n                    }\n                }\n            }\n            #endregion\n        }\n        #endregion\n\n        #region PROCESS_CALLACK\n        private async Task ProcessCallbackQuery(TdApi.Update.UpdateNewCallbackQuery callbackQuery)\n        {\n            if (callbackQuery.Payload.GetType() == typeof(TdApi.CallbackQueryPayload.CallbackQueryPayloadData))\n            {\n                var payload = callbackQuery.Payload as TdApi.CallbackQueryPayload.CallbackQueryPayloadData;\n                var callbackHandlers = GetAll<ICallbackHandler>();\n                foreach (var handler in callbackHandlers)\n                {\n                    if (handler.DataIsRegex)\n                        if (Regex.Match(System.Text.Encoding.UTF8.GetString(payload.Data), handler.Data).Success)\n                            await handler.ExecuteAsync(_client, callbackQuery);\n                    else if (handler.Data == System.Text.Encoding.UTF8.GetString(payload.Data))\n                        await handler.ExecuteAsync(_client, callbackQuery);\n                }\n            }\n        }\n        #endregion\n\n        #region COMMAND_PARSER\n        public string GetCommand(TdApi.Message message)\n        {\n            string command = null;\n            TdLib.TdApi.FormattedText formattedText = new TdLib.TdApi.FormattedText();\n            if (message.Content.GetType() == typeof(TdLib.TdApi.MessageContent.MessageText))\n            {\n                var messageText = message.Content as TdLib.TdApi.MessageContent.MessageText;\n                formattedText = messageText.Text;\n            }\n            else\n            {\n                if (message.Content.GetType() == typeof(TdLib.TdApi.MessageContent.MessagePhoto))\n                {\n                    var messagePhoto = message.Content as TdLib.TdApi.MessageContent.MessagePhoto;\n                    formattedText = messagePhoto.Caption;\n                }\n                else if (message.Content.GetType() == typeof(TdLib.TdApi.MessageContent.MessageDocument))\n                {\n                    var messageDocument = message.Content as TdLib.TdApi.MessageContent.MessageDocument;\n                    formattedText = messageDocument.Caption;\n                }\n                else if (message.Content.GetType() == typeof(TdLib.TdApi.MessageContent.MessageVideo))\n                {\n                    var messageVideo = message.Content as TdLib.TdApi.MessageContent.MessageVideo;\n                    formattedText = messageVideo.Caption;\n                }\n            }\n\n            foreach (var entity in formattedText.Entities)\n            {\n                if (entity.Type.GetType() == typeof(TdLib.TdApi.TextEntityType.TextEntityTypeBotCommand) && String.IsNullOrWhiteSpace(command))\n                {\n                    if (entity.Offset == 0)\n                    {\n                        var splitCommand = formattedText.Text.Split();\n                        if (splitCommand[0].EndsWith($"@{_me.Username}"))\n                        {\n                            command = splitCommand[0].Split(\'@\')[0];\n                        }\n                        else\n                        {\n                            command = splitCommand[0];\n                        }\n                    }\n                }\n            }\n            return command;\n        }\n        #endregion\n\n        #region MESSAGE_PARSER\n\n        public string GetMessageText(TdApi.Message message)\n        {\n            TdLib.TdApi.FormattedText formattedText = new TdLib.TdApi.FormattedText();\n            if (message.Content.GetType() == typeof(TdLib.TdApi.MessageContent.MessageText))\n            {\n                var messageText = message.Content as TdLib.TdApi.MessageContent.MessageText;\n                formattedText = messageText.Text;\n            }\n            else\n            {\n                if (message.Content.GetType() == typeof(TdLib.TdApi.MessageContent.MessagePhoto))\n                {\n                    var messagePhoto = message.Content as TdLib.TdApi.MessageContent.MessagePhoto;\n                    formattedText = messagePhoto.Caption;\n                }\n                else if (message.Content.GetType() == typeof(TdLib.TdApi.MessageContent.MessageDocument))\n                {\n                    var messageDocument = message.Content as TdLib.TdApi.MessageContent.MessageDocument;\n                    formattedText = messageDocument.Caption;\n                }\n                else if (message.Content.GetType() == typeof(TdLib.TdApi.MessageContent.MessageVideo))\n                {\n                    var messageVideo = message.Content as TdLib.TdApi.MessageContent.MessageVideo;\n                    formattedText = messageVideo.Caption;\n                }\n            }\n            return formattedText.Text;\n        }\n\n        #endregion\n\n        #region REFLECTION\n        // https://stackoverflow.com/a/41650057/15306888\n        public static IEnumerable<T> GetAll<T>()\n        {\n            return Assembly.GetExecutingAssembly()\n                .GetTypes()\n                .Where(type => typeof(T).IsAssignableFrom(type))\n                .Where(type =>\n                    !type.IsAbstract &&\n                    !type.IsGenericType &&\n                    type.GetConstructor(new Type[0]) != null)\n                .Select(type => (T)Activator.CreateInstance(type))\n                .ToList();\n        }\n        #endregion\n    }\n}\n\n
Run Code Online (Sandbox Code Playgroud)\n

Mic*_*aum 5

由于它始终为空,我认为问题在于您没有创建处理程序的实例。我为您准备了一个演示,我做到了这一点并且有效。

public interface ICommandHandler 
{
    string Command { get; }
    Task ExecuteAsync();
}
public class FirstCommandHandler : ICommandHandler
{
    public string Command => "First";

    public async Task ExecuteAsync()
    {
        Console.WriteLine("Hello from first.");
        await Task.Delay(10);
    }
}
public class SecondCommandHandler : ICommandHandler
{
    public string Command => "Second";

    public async Task ExecuteAsync()
    {
        Console.WriteLine("Hello from second.");
        await Task.Delay(10);
    }
}

public class Program
{
    static async Task Main(string[] args)
    {
        var handlers = AppDomain.CurrentDomain.GetAssemblies()
            .SelectMany(s => s.GetTypes())
            .Where(p => typeof(ICommandHandler).IsAssignableFrom(p) && p.IsClass);

        foreach (var handler in handlers)
        {
            var handlerInstance = (ICommandHandler)Activator.CreateInstance(handler);
            if (handlerInstance.Command == "First")
            {
                await handlerInstance.ExecuteAsync();
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

如果不是这样,您能显示更多代码吗?您是否想通过反思来检查Command价值?