解析和代理的命令 [英] Parsing and Acting on commands

查看:170
本文介绍了解析和代理的命令的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在为我的项目调试控制台,以从文本框



输入

不过我想知道,如果有任何替代简直就是一个巨大的switch语句:

 开关(command.ToLower){
案榜样:
//做的事情......
中断;
案示例2:
//做的事情......
中断;
}



,因为我觉得还有一个更优雅的解决方案avaliable,但是我的技能无法对其进行访问



编辑:
由于@OwlSolo惊人的贡献,现在我有我的代码工作,我已经发布我下面的修改代码的版本提出,是对我工作。感谢@OwlSolo你是一个传奇打字!



 类parseCommand 
{
公共静态commandBase commandInstance {得到;组; }

公共静态无效解析(字符串命令)
{
的String []标记= command.Split(''); //令牌[0]是原始命令
对象[]参数= tokens.Skip(1).ToArray();

名单,LT;类型> cmdTypes = System.Reflection.Assembly
.GetExecutingAssembly()
.GetTypes()
。凡(T => typeof运算(commandBase).IsAssignableFrom(T))
.ToList ();

的foreach(类型derivedType在cmdTypes)
{
如果(derivedType.Name.ToLower()==令牌[0] .ToLower())
$ { b $ b commandInstance =(commandBase)Activator.CreateInstance(derivedType);
commandInstance.parameters =参数;
commandInstance.Execute();
中断;
}
}
}
}


解决方案

解析某种形式的语言基本上本身就是一个完整的学科,所以这个问题是相当广泛的。
语言的词法分析器和解析器通常会产生这是在保留关键字和参数隔开的命令树结构。保留关键字包含例如命令。 (如开关如果转到等。在C语言的语言)
的一点是,这些命令的方式最好选择,使他们相互独立的。这意味着,在本身的关键字惹一个非常不同的处理方式。微调是通过参数来实现。



如果这适用于你的命令,你没有多少选择的余地,以提供处理每个命令独立的方法。比如JavaCC的(JavaCompiler的编译器)生成的代码库与生成指令树相当大的开关情况。然后由用户来评估提供的使用说明树,通常是通过该处理的关键字个别对象进行 - 所以有可能是一类 IfStatement 持有多项孩子的指令和处理它的执行。



不管你特别需要在这里,真正的工作将是,你如何处理的执行,而不是你如何区分哪些命令调用哪个。行为



您可能想可能看起来像这样的结构:

 抽象类BinaryCommand 
{
MyBaseCommand child1;
MyBaseCommand的child2;

抽象对象执行();
}

类ExampleCommand1:BinaryCommand
{
改写对象Execute()
{
// DoStuff1 ...
}
}

类ExampleCommand2:BinaryCommand
{
改写对象Execute()
{
//做别的Somethign
}
}

至于关键字之间进行区分,有多种方法:




  • 一个大的switch语句。


  • 拿着词典<字符串类型> 从中查找处理命令的类型。因此,例如:例1 ABCDE 12345将查找例1,创建字典类型的实例,并与参数ABCDE和12345


  • FIL它。
  • 一个非常大胆的方式是通过你的可以处理命令类代码来反映。结果
    你将不得不像 IBaseCommand 从你命令类派生。




  //获取所有从你的基本类型
名单,LT派生类型;类型> commandTypes =大会
.GetExecutingAssembly()
.GetTypes()
。凡(T => typeof运算(IBaseCommand).IsAssignableFrom(T));

的foreach(类型derivedType在commandTypes)
{
//通过类名称区别可能不是最好的解决办法在这里,但只给你的总体思路
如果(derivedType.Name == command.ToLower)
{
//创建命令类型$ b $乙IBaseCommand myCommandInstance = Activator.CreateInstance(derivedType)的实例;
//调用execute方法,任何知道该怎么做
myCommandInstance.Execute();
}
}



编辑:随着在评论中提供的信息,你可以做这样的事情。

 接口ICommandBase 
{
对象[]参数{搞定;设置;}
无效执行();
}

抽象类InternalCommand:ICommandBase
{
//一些方法是共同的所有intzernal命令
}

类SetColorCommand:// InternalCommand或者它可能会从ICommandBase直接派生,如果你不需要它归类
{
的对象[]参数{搞定;设置;}
无效执行()
{
开关(参数[0])
{
案背景:
//设置背景颜色参数[1]
中断;
案前景:
// ...
中断;
}
}
}

类的SqlCommand:ICommandBase
//或者,它可能会从ICommandBase获得直接,如果你不需要它归类
{
的对象[]参数{搞定;设置;}
无效执行()
{
//参数[0]将是SQL字符串...
}
}

然后通过分析整个事情:

  //假设你每行得到一个命令和一行被送到这个功能
公共无效ParseCommands(字符串命令)
{
的String []标记=命令。分裂( );
//令牌[0]是命令名称
对象[]参数=(对象[])tokens.Skip(1); //将一切,但第一个元素(你需要包括对LINQ这一点)

//获取所有从基类
名单,LT派生类型;类型> commandTypes =大会
.GetExecutingAssembly()
.GetTypes()
。凡(T => typeof运算(IBaseCommand).IsAssignableFrom(T));

的foreach(类型derivedType在commandTypes)
{
如果(derivedType.Name.ToLower ==令牌[0] .ToLower)
/ *这里的类名需要匹配的CommandName;这yould也可以是
静态属性,姓名,也就是通过反射提取从类
实例,或者你把你所有的命令在字典<字符串,键入>和查找
令牌[0] *词典/
{
//创建命令类型
IBaseCommand myCommandInstance = Activator.CreateInstance(derivedType)的实例;
myCommandInstance.parameters =参数;
myCommandInstance.Execute(); //调用execute方法,任何知道该怎么做
中断;
}
}
}

您的目标是有作为一些命令尽可能做尽可能多的,你可以通过参数。


I am making a debugging console for my projects, taking input from a TextBox, etc.

However I wish to know if there are any alternatives to simply a huge switch statement:

switch(command.ToLower) {
case "example":
    // do things...
    break;
case "example2":
    // do things...
    break;
}

As I feel there is a more elegant solution avaliable but my skills cannot access it.

EDIT: Due to the amazing contribution of @OwlSolo I now have my code working, I have posted below my modified version of the code submitted that is functioning for me. Thanks @OwlSolo you are an legend typing!

class parseCommand
{
    public static commandBase commandInstance { get; set; }

    public static void parse(string command)
    {
        string[] tokens = command.Split(' '); // tokens[0] is the original command
        object[] parameters = tokens.Skip(1).ToArray();

        List<Type> cmdTypes = System.Reflection.Assembly
            .GetExecutingAssembly()
            .GetTypes()
            .Where(t => typeof(commandBase).IsAssignableFrom(t))
            .ToList();

        foreach(Type derivedType in cmdTypes)
        {
            if (derivedType.Name.ToLower() == tokens[0].ToLower())
            {
                commandInstance = (commandBase)Activator.CreateInstance(derivedType);
                commandInstance.parameters = parameters;
                commandInstance.Execute();
                break;
            }
        }
    }
}

解决方案

Parsing a language of some kind is basically a whole discipline in itself, so this question is rather broad. Language lexers and parsers generally create tree structures of commands which are separated in reserved keywords and parameters. The reserved keywords contain for instance commands. (such as switch, if, goto, etc. in C-like languages) The thing is, that these commands are ideally chosen in a way so that they're mutually independent. That means that the keywords in itself provoke a very different handling. The fine tuning is done via the parameters.

If this applies to your commands, you don't have much of a choice as to provide independent methods of handling each command. For instance the JavaCC (JavaCompiler-Compiler) generates a code base with rather large switch cases that generate an instruction tree. It is then up to the user to evaluate the provided instruction tree which is usually done via individual objects that handle the keywords - so there could be a class IfStatement which holds a number of child instructions and handles its execution.

Whatever you need here specifically, the real work is going to be, how you handle the execution rather than how you differentiate which command invokes which behavior.

A structure you might want could look something like this:

abstract class BinaryCommand
{
    MyBaseCommand child1;
    MyBaseCommand child2;

    abstract object Execute();
}

class ExampleCommand1 : BinaryCommand
{
    override object Execute()
    {
         //DoStuff1...
    }
}

class ExampleCommand2 : BinaryCommand
{
    override object Execute()
    {
         //Do Somethign else
    }
}

As for differentiating between your keywords, there is a number of ways:

  • A large switch statement.

  • Holding a Dictionary<string, Type> from which you look up the Type that handles a command. So for instance: "Example1 abcde 12345" would lookup "Example1", create an instance of the type in the dictionary and fil it with the parameters "abcde" and "12345".

  • A rather bold way would be to reflect through your code for a class that can handle the command.
    You would have an interface like IBaseCommand from which all you command classes derive.

// Get all the types that derive from your base type
List<Type> commandTypes = Assembly
    .GetExecutingAssembly()
    .GetTypes()
    .Where(t => typeof(IBaseCommand).IsAssignableFrom(t));

foreach (Type derivedType in commandTypes)
{
    // Distinguishing by class name is probably not the best solution here, but just to give you the general idea
    if (derivedType.Name == command.ToLower) 
    {
        // Create an instance of the command type
        IBaseCommand myCommandInstance = Activator.CreateInstance(derivedType);
        //Call the execute method, that knows what to do
        myCommandInstance.Execute();
    }
}

EDIT: With the information provided in the comments, you could do something like this

Interface ICommandBase
{
    object[] parameters {get; set;}
    void Execute();    
}

abstract class InternalCommand : ICommandBase
{
    //Some methods that are common to all your intzernal commands
}

class SetColorCommand : InternalCommand //Or it might derive from ICommandBase directly if you dont need to categorize it
{
     object[] parameters {get; set;}
     void Execute()
     {
         switch (parameters[0])
         {
              case "background":
                  //Set the background color to parameters[1]
              break;
              case "foreground":
                    //...
              break;
         }
     }
}

class SqlCommand : ICommandBase
// Or it might derive from ICommandBase directly if you don't need to categorize it
{
     object[] parameters {get; set;}
     void Execute()
     { 
          //Parameters[0] would be the sql string...
     } 
}

Then parse the whole thing via:

// Assuming you're getting one command per line and one line is fed to this function
public void ParseCommands(string command)
{
    string[] tokens = command.Split(" ");
    // tokens[0] is the command name
    object[] parameters = (object[])tokens.Skip(1);//Take everything but the first element (you need to include LINQ for this)

    // Get all the types that derive from your base type
    List<Type> commandTypes = Assembly
        .GetExecutingAssembly()
        .GetTypes()
        .Where(t => typeof(IBaseCommand).IsAssignableFrom(t));

    foreach (Type derivedType in commandTypes)
    {
        if (derivedType.Name.ToLower == tokens[0].ToLower) 
        /* Here the class name needs to match the commandname; this yould also be a
           static property "Name" that is extracted via reflection from the classes for 
           instance, or you put all your commands in a Dictionary<String, Type> and lookup 
           tokens[0] in the Dictionary */
        {
            // Create an instance of the command type
            IBaseCommand myCommandInstance = Activator.CreateInstance(derivedType);
            myCommandInstance.parameters = parameters;
            myCommandInstance.Execute(); // Call the execute method, that knows what to do
                 break;
        }
    }   
}

You goal is to have as few commands as possible and do as much as you can via the parameters.

这篇关于解析和代理的命令的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆