天天看點

[C#] 使用 NullLib.CommandLine 分析指令行字元串并執行與代碼中定義的方法摘要介紹NullLib.CommandLine

摘要介紹

通過指令行字元串來友善快捷的調用 C# 中定義的方法

準備

  1. 添加 nuget 包: NullLib.CommandLine

使用方式

首先, 在 NullLib.CommandLine 中用于調用方法的最基本類型是

CommandObject

, 它包含了方法的各種資訊, 例如

MethodInfo

,

ParameterInfo

, 以及屬性.

然後, 你需要定義一個包含要調用方法的類, 在這個類中, 每一個将被調用的方法都應該有一個

Command

屬性, 之後我們将用這個類型執行個體化一個

CommandObject

執行個體.

一個示例類型:

public class AppCommands
{
    [Command]
    public void HelloWorld()
    {
        Console.WriteLine("Hello world!");
    }
}
           

執行個體化一個

CommandObject

對象, 然後循環執行指令.

using System;
using NullLib.CommandLine;

class Program
{
    static CommandObject<AppCommands> AppCommandObject = new CommandObject<AppCommands>();   // 執行個體化一個 CommandObject 對象
    static void Main(string[] args)
    {
        Console.WriteLine("Now input commands.");
        while (true)
        {
            Console.Write(">>> ");          // 提示符
            string cmdline = Console.ReadLine();
            if (!AppCommandObject.TryExecuteCommand(cmdline, out var result))
            {
                if (result != null)             // 如果一個方法沒有傳回值, 則結果是 null.
	                Console.WriteLine(result);
            }
            else
            {
                Console.WriteLine("Command execute failed.");
            }
        }
    }
}
           

運作程式, 并輸入指令:

Now input commands.
>>> HelloWorld
Hello world!
           

為每一個參數指定

ArgumentConverter

以傳遞參數到方法.

那麼, 我們再試試将這些方法添加到

AppCommands

[Command(typeof(FloatArguConverter), typeof(FloatArguConverter))]      // NullLib.CommandLine 中的内置 ArgumentConverter
public float Plus(float a, float b)
{
    return a + b;
}
[Command(typeof(FloatArguConverter))]        // 如果跟着的轉換器與上一個是一樣的, 那麼你可以忽略它們
public float Mul(float a, float b)
{
    return a * b;
}
[Command(typeof(DoubleArguConverter))]
public double Log(double n, double newBase = Math.E)    // 你也可以使用可選參數
{
    return Math.Log(n, newBase);
}
[Command(typeof(ForeachArguConverter<FloatArguConverter>))]   // 數組中的每一個字元串都将被 FloatArguConverter 轉換
public float Sum(params float[] nums)                 // 可變參數的方法也是受支援的
{
    float result = 0;
    foreach (var i in nums)
        result += i;
    return result;
}
[Command(typeof(ArgutConverter))]        // 如果不需要做任何轉換, 則可以指定一個 'ArguConverter'
public void Print(string txt)
{
    Console.WriteLine(txt);
}
[Command]                                // 預設的轉換器是 'ArguConverter', 在這種情況下你可以忽略它們
public bool StringEquals(string txt1, string txt2)   // 或者指定 'null' 來使用上一個轉換器(在這裡指 ArguConverter)
{
    return txt1.Equals(txt2);
}
[Command(typeof(EnumArguConverter<ConsoleColor>))]   // EnumConverter 可以用來将字元串自動轉換為枚舉類型
public void SetBackground(ConsoleColor color)
{
    Console.BackgroundColor = color;
}
           

Run and input:

Now input commands.
>>> Plus 1 1
2
>>> Mul 2 4
8
>>> Log 8 2
3
>>> Log 8
2.07944154167984
>>> Sum 1 2 3 4
10
>>> Print "一些文本\t轉義字元也是受支援的"
一些文本	轉義字元也是受支援的
>>> StringEquals qwq awa
False
>>> SetBackground White
>>> SetBackground 0
           

更多

通過這個庫, 你可以通過指令行字元串友善快捷的調用 C# 中定義的方法, 甚至于通過一些方法實作簡單的, 類似于 CMD 指令提示符的指令解釋器, 完整文檔,

NullLib.CommandLine

通過指令行字元串來友善快捷的調用 C# 中定義的方法

使用方式

首先, 在 NullLib.CommandLine 中用于調用方法的最基本類型是

CommandObject

, 它包含了方法的各種資訊, 例如

MethodInfo

,

ParameterInfo

, 以及屬性.

然後, 你需要定義一個包含要調用方法的類, 在這個類中, 每一個将被調用的方法都應該有一個

Command

屬性, 之後我們将用這個類型執行個體化一個

CommandObject

執行個體.

一個示例類型:

public class AppCommands
{
    [Command]
    public void HelloWorld()
    {
        Console.WriteLine("Hello world!");
    }
}
           

執行個體化一個

CommandObject

對象, 然後循環執行指令.

using System;
using NullLib.CommandLine;

class Program
{
    static CommandObject<AppCommands> AppCommandObject = new CommandObject<AppCommands>();   // 執行個體化一個 CommandObject 對象
    static void Main(string[] args)
    {
        Console.WriteLine("Now input commands.");
        while (true)
        {
            Console.Write(">>> ");          // 提示符
            string cmdline = Console.ReadLine();
            if (!AppCommandObject.TryExecuteCommand(cmdline, out var result))
            {
                if (result != null)             // 如果一個方法沒有傳回值, 則結果是 null.
	                Console.WriteLine(result);
            }
            else
            {
                Console.WriteLine("Command execute failed.");
            }
        }
    }
}
           

運作程式, 并輸入指令:

Now input commands.
>>> HelloWorld
Hello world!
           

為每一個參數指定

ArgumentConverter

來以傳遞參數到方法.

那麼, 我們再試試将這些方法添加到

AppCommands

[Command(typeof(FloatArguConverter), typeof(FloatArguConverter))]      // NullLib.CommandLine 中的内置 ArgumentConverter
public float Plus(float a, float b)
{
    return a + b;
}
[Command(typeof(FloatArguConverter))]        // 如果跟着的轉換器與上一個是一樣的, 那麼你可以忽略它們
public float Mul(float a, float b)
{
    return a * b;
}
[Command(typeof(DoubleArguConverter))]
public double Log(double n, double newBase = Math.E)    // 你也可以使用可選參數
{
    return Math.Log(n, newBase);
}
[Command(typeof(ForeachArguConverter<FloatArguConverter>))]   // 數組中的每一個字元串都将被 FloatArguConverter 轉換
public float Sum(params float[] nums)                 // 可變參數的方法也是受支援的
{
    float result = 0;
    foreach (var i in nums)
        result += i;
    return result;
}
[Command(typeof(ArgutConverter))]        // 如果不需要做任何轉換, 則可以指定一個 'ArguConverter'
public void Print(string txt)
{
    Console.WriteLine(txt);
}
[Command]                                   // 預設的轉換器是 'ArguConverter', 在這種情況下你可以忽略它們
public bool StringEquals(string txt1, string txt2)   // 或者指定 'null' 來使用上一個轉換器(在這裡指 ArguConverter)
{
    return txt1.Equals(txt2);
}
[Command(typeof(EnumArguConverter<ConsoleColor>))]   // EnumConverter 可以用來将字元串自動轉換為枚舉類型
public void SetBackground(ConsoleColor color)
{
    Console.BackgroundColor = color;
}
           

Run and input:

Now input commands.
>>> Plus 1 1
2
>>> Mul 2 4
8
>>> Log 8 2
3
>>> Log 8
2.07944154167984
>>> Sum 1 2 3 4
10
>>> Print "一些文本\t轉義字元也是受支援的"
一些文本	轉義字元也是受支援的
>>> StringEquals qwq awa
False
>>> SetBackground White
>>> SetBackground 0
>>> Print "你可以通過一個枚舉類型的名字或整數值來進行轉換"
你可以通過一個枚舉類型的名字或整數值來進行轉換
           

Types

  1. CommandAttribute:

    可以通過指令行字元串執行的方法必須有一個

    CommandAttribute

    屬性
  2. CommandObject:

    用于使用指令行字元串調用方法的類

  3. CommandInvoker:

    幫助通過

    IArguments

    調用方法
  4. CommandParser:

    幫助分析指令行字元串以調用方法

  5. ArgumentConverter:

    繼承

    IArgumentConverter

    接口, 抽象類, 應該被自定義轉換器繼承
  6. ArgumentConverterManager:

    幫助快速建立

    ArgumentConverter

  7. CommandLineSegment:

    指令行字元串的構成部分

  8. ArgumentParser:

    幫助将

    CommandLineSegment

    分析為

    IArgument

CommandLineSegment

CommandLineSegment 是指令行字元串的組成部分

例如, 在

myprogram param1 "param2"

中, 有三個 CommandLineSegment:

  1. {Quoted: false, Content: “myprogram”}
  2. {Quoted: false, Content: “param1”}
  3. {Quoted: true, Content: “\“param2\””}

将指令行字元串分割為 CommandLineSegment[], 使用

CommandParser.SplitCommandLine(string str)

Argument

指令的參數, 可有名稱, 繼承

IArgument

, 當調用方法時, 将會被傳遞

ArgumentParser

下面是所有内置的

ArgumentParsers

  1. ArguParser:

    可将任何部分分析為一個

    Argument

  2. IdentifierArguParser:

    可将一個辨別符部分分析為一個

    Argument

    . 對應的正規表達式是 “{A-Za-z_}{A-Za-z0-9_}*”
  3. StringArguParser:

    可以将任何 Quoted(被雙引号包圍的) 部分分析為

    Argument

  4. FieldArguParser:

    可以将像 name=value 的一個部分, 或者像 name= value 的兩個部分分析為一個

    Argument

    , 另外, 你可以指定分隔符, 預設分隔符是 ‘=’
  5. PropertyArguParser:

    可以将像 -name value 的兩個部分分析為

    Argument

    , 并且你也可以指定 name 的起始字元串, 預設是 “-”

ArgumentConverter

Here is all build-in

ArgumentConverter

:

  1. ArguConverter:

    不會做任何轉換而直接傳回源值的預設的

    ArgumentConverter

  2. BoolArguConverter:

    幫助轉換到布爾值, 使用 bool.Parse 和 bool.TryParse

  3. CharArguConverter:

    幫助轉換到字元, 僅當字元串有唯一一個字元時, 傳回這個字元, 否則轉換失敗

  4. ByteArguConverter:
  5. ShortArguConverter:
  6. IntArguConverter:
  7. LongArguConverter:
  8. FloatArguConverter:
  9. DoubleArguConverter:
  10. BigIntArguConverter:
  11. DecimalArguConverter:

    上面提到的轉換器均傳回對應的數字類型, 并且它們都通過調用對應類型的

    Parse

    TryParse

    方法實作轉換
  12. EnumArguConverter<T>:

    幫助轉換到枚舉類型, T 應該被指定為一個枚舉類型. 它可以從枚舉值的名稱或數字值來轉換

  13. ForeachArguConverter<TConverter>:

    幫助轉換到一個數組, 僅用于可變參數(使用

    params

    修飾),

    TConverter

    必須實作

    IArgumentConverter

    接口, 每個值都将被指定的轉換器轉換, 最終得到一個對應類型的數組.
  14. CharArrayArguConverter:

    幫助轉換到字元數組, 它調用

    string.ToCharArray()

    來進行轉換.

About ArgumentParser

Custom Parser:

定義自定義的

ArgumentParser

, 你需要遵守下面的規則:

  1. 實作

    IArgumentParser

    接口
  2. 在分析完畢後, 引用參數

    index

    必須離開參數結果(IArgument)的區域, 例如, 在索引 3, 在你的自定義分析器中, 他将傳回結果 (結果被成功分析), 并且分析結果來自于兩個

    CommandLineSegment

    , 是以

    index

    必須是 5 (在 3 和 4 之外).

About ArgumentConverter

自定義 Converter:

定義自定義

ArgumentConverter

的推薦方式是這樣:

class MyConverter : ArgumentConverter<MyType>    // 繼承 ArgumentConverter<T> 而不是 IArgumentConverter<T>
{
    public override MyType Convert(string argument)
    {
        // 你的代碼
    }
    public override bool TryConvert(string argument, out MyType result)
    {
        // 你的代碼
    }
}
           

繼承

ArgumentConverter<T>

而不是

IArgumentConverter<T>

的原因是, 在

ArgumentConverter<T>

中, 所有方法重載均調用這兩個方法:

  1. T Convert(string argument);
  2. bool TryConverter(string argument, out T result);

是以如果繼承

ArgumentConverter<T>

, 你隻需要重寫這兩個方法.

Tips:

  1. 不要使用 new 表達式來建立一個

    ArgumentConverter

    執行個體, 請使用

    ArgumentConverterManager.GetConverter<T>()

    .

FAQ

  1. 當我調用

    CommandObject.ExecuteCommand(IArgumentParser[] parsers, string cmdline)

    時, 某些分析器不能正常使用:
    // 你必須以正确的順序指定分析器, 否則就會這樣:
    CommandObject<AppCommands> myCmds = new CommandObject<AppCommands>();
    myCmds.ExecuteCommand(new IArgumentParser[]
    {
        new ArguParser(),                // 在這種情況下, FieldArguParser 和 PropertyArguParser 将不起作用.
        new FieldArguParser(),           // 這是因為 ArguParser 可以分析任何 CommandLineSegments, 是以你應該
        new PropertyArguParser()         // 将 ArguParser 作為最後一個分析器, 這樣分析的時候就會先使用前兩個
    }, Console.ReadLine());