C# 属性和方法

C# attributes and methods

大家好, 最近我遇到了 Discord.NET Api 并爱上了命令的处理方式。本质上,要添加一个在你写 !ping 时执行的新命令,你可以这样做:

[Command("ping")]
public async Task Ping()
{
    //some logic here
}

而且我真的很喜欢在现有 API 中集成新命令的简单性。所以我想重现正在发生的事情。一开始我被元编程的引入搞得一头雾水,现在感觉舒服了一点,于是尝试下手,设计了一个只能赋值给方法的Attribute:


[AttributeUsage(AttributeTargets.Method)]
    public class Command : Attribute
    {
        
        public string Name { get; set; }

        public Command(string name)
        {
            Name = name;
        }
        public Command()
        {
            Name = string.Empty;
        }
    }

然后的基本想法是,当我的控制台收到命令时,我可以 运行 一个方法,该方法具有命令属性和在控制台中输入的名称。因此,当我在控制台中输入“ping”时,将执行以下方法。

[Command("ping")]
public void Ping()
{
    //do sth 
}

现在进入复杂的部分。我如何找到特别是 运行 那个方法?那就是我现在被困的地方。在 .Net 纪录片或这里的 Whosebug 上,我真的没有发现任何关于这个问题的有用信息。无论如何,这是我的尝试:

public void Handle(string command)
{
    var methods = from t in Assembly.GetExecutingAssembly().GetTypes()
                  where t.GetCustomAttributes<Command>().Count() > 0
                  select t;
     //run method where command.name = ping
}

其背后的想法是,遍历程序集中所有可用的方法,然后将它们放入某种列表中,然后执行具有传入内容的 command.name 的方法Handle 函数的参数。当我让它工作时,我当然会在 class 的构造函数中初始化方法列表,而不是每次在调用 Handle 时调用它,但是为了简单起见,我的问题独立于此,以让我的例子最少。现在的问题是,如何遍历程序集中的所有方法,并将具有 command 属性的方法保存到集合中,以及如何 运行 具有特定值的方法 command.Name 属性? 我对整个反射的东西有点陌生,所以如果我做了其他愚蠢的事情或者你有关于那个主题的一般提示,请告诉我!! 提前致谢!!

我已经编写了一个小型演示应用程序,应该可以帮助您完成您的逻辑。总的来说,当然,它仍然有改进的空间,但它是有效的:

using System;
using System.Linq;
using System.Reflection;

namespace DemoApp
{
    class Program
    {
        static void Main(string[] args)
        {
            string command = Console.ReadLine().Trim();

            LogicProvider provider = new LogicProvider();
            MethodInfo method = provider.GetType().GetMethods().FirstOrDefault((item) => item.GetCustomAttribute<CommandAttribute>().Identifier == command);
            method?.Invoke(provider, null);
        }
    }

    public class LogicProvider
    {
        [Command("DemoCommand")]
        public void MyMethod()
        {
            Console.WriteLine("Here");
        }
    }

    public class CommandAttribute : Attribute
    {
        public CommandAttribute(string identifier)
        {
            this.Identifier = identifier;
        }

        public string Identifier { get; } = null;
    }
}

如果在控制台中输入 DemoCommand,则会在 LogicProvider 中搜索匹配方法。如果匹配,则执行。

整个过程也适用于具有参数的方法。在 method?.Invoke() 的情况下,这可以被指定。