Mar*_*dru 1 c# reflection .net-core
如果特定类的字符串成员与给定的字符串成员匹配,如何获取实现特定接口的所有类,然后调用该类的函数?
\n基本上我拥有的是一个ICommandHandler界面:
interface ICommandHandler\n{\n string Command { get; }\n Task ExecuteAsync();\n}\nRun Code Online (Sandbox Code Playgroud)\n以及一个实现它的类:
\npublic class StartCommand : ICommandHandler\n{\n\n public string Command { get => "start"; }\n public async Task ExecuteAsync()\n {\n // do something\n }\n}\nRun Code Online (Sandbox Code Playgroud)\n我想要做的是获取所有实现 ICommandHandler 接口的类,然后验证是否class.Command等于特定字符串,如果等于则调用该ExecuteAsync方法。
我尝试在这里使用这个答案: https: //stackoverflow.com/a/45382386/15306888但class.Command总是null
编辑:我得到的答案做了我想做的事情:
\n我正在寻找一种使用 ICommandHandler 的方法,让我可以轻松收集从它继承的所有类并调用该函数,ExecuteAsync而不必在处理 TdLib 消息事件的代码部分中手动添加方法。
所以现在我的项目目录看起来像这样:
\nTelegramClient.cs- 加载从 ICommandHandler 继承的类的位置,ExecuteAsync如果 Command 成员与从电报返回的消息中解析的 Command 匹配,则调用该方法。Handlers/- 我的处理程序的基本目录\nCommandHandlers/- 包含ICommandHandler接口和继承自它的类的文件夹MessageHandlers/- 具有另一个接口IMessageHandler和继承自它的类的文件夹不管怎样,与此同时,我在 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 }\nRun 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 }\nRun Code Online (Sandbox Code Playgroud)\n接口的实际实现方式:
\nusing 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\nRun Code Online (Sandbox Code Playgroud)\n完整的 TelegramClient 类:
\nusing 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\nRun Code Online (Sandbox Code Playgroud)\n
由于它始终为空,我认为问题在于您没有创建处理程序的实例。我为您准备了一个演示,我做到了这一点并且有效。
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价值?
| 归档时间: |
|
| 查看次数: |
3928 次 |
| 最近记录: |