将可能有参数或没有参数的函数存储到变量中。 Action<T> 具有未知数量和类型的变量

Storing a function that may have parameter or not, to variable. Action<T> with unknown numbers and types of variables

我正在为控制台应用程序开发命令解析器 class,但我被困在将命令函数存储到变量中。我想将一个可能有参数或没有参数的函数存储到 Command 对象中的 commandFunc 变量。

这些代码适用于不带参数的函数。如何获得对此的参数支持?例如:像 output(string msg){ .. }

这样的函数
class Program
{
    static void Main(string[] args)
    {
        CommandParser.AddCommand(new Command() { commandText = "time", commandFunc = new Action(time) });

        CommandParser.Loop();
    }

    private static void time()
    {
        Console.WriteLine(DateTime.Now.ToLongTimeString());
    }
}

在 CommandParser.Loop 中,它在 List< Command > 中搜索输入的命令,然后从中运行 Execute 方法。

public class Command
{
    public string commandText { get; set; }
    public Action commandFunc { get; set; }

    public void Execute()
    {
        this.commandFunc();
    }
}

例如执行方法可以是这样的:

public void Execute(Parameters params)
{
    this.commandFunc(params);
}

PS: CommandParser.Loop()

    public static void Loop()
    {
        while(true)
        {
            Console.Write(prefix);
            string[] input = Console.ReadLine().Split(' ');

            Command cmdInput = commands.Find(x => x.commandText.Contains(input[0]));
            if(cmdInput != new Command())
            {
                cmdInput.Execute();
            }
            else
            {
                Console.WriteLine(prefix + "Command not found!");
            }
        }
    }

嗯,您基本上需要做的是扩展对象层次结构。

在C#中,泛型不允许Something<void>,所以你需要做的是:

public interface ICommand
{
    void Execute();
}

这是添加了接口的当前实现

public class Command : ICommand
{
    public string commandText { get; set; }
    public Action commandFunc { get; set; }

    public void Execute()
    {
        this.commandFunc();
    }
}

并且是带参数的委托的通用实现

public class Command<T> : ICommand
{
    public string       commandText  { get; set; }
    public Action<T>    commandFunc  { get; set; }
    public T            commandParam { get; set; }

    public void Execute()
    {
        this.commandFunc(commandParam);
    }
}

如果您需要实现更多参数,您可以复制原始参数或使用 Tuple class 作为通用参数(例如 Tuple<string, int>)。

正如 Jon Skeet 在评论中提到的:
另一件事是您可能需要解析这些通用命令中的参数(由 commandParam 表示)。您应该使用参数(例如委托)初始化这些命令以解析参数。在命令之外执行此操作会一团糟,并破坏整个 genericity/interface 想法。但它可能适用于较小的规模。