摘要介紹
通過指令行字元串來友善快捷的調用 C# 中定義的方法
準備
- 添加 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
-
CommandAttribute:
可以通過指令行字元串執行的方法必須有一個
屬性CommandAttribute
-
CommandObject:
用于使用指令行字元串調用方法的類
-
CommandInvoker:
幫助通過
調用方法IArguments
-
CommandParser:
幫助分析指令行字元串以調用方法
-
ArgumentConverter:
繼承
接口, 抽象類, 應該被自定義轉換器繼承IArgumentConverter
-
ArgumentConverterManager:
幫助快速建立
ArgumentConverter
-
CommandLineSegment:
指令行字元串的構成部分
-
ArgumentParser:
幫助将
分析為CommandLineSegment
IArgument
CommandLineSegment
CommandLineSegment 是指令行字元串的組成部分
例如, 在
myprogram param1 "param2"
中, 有三個 CommandLineSegment:
- {Quoted: false, Content: “myprogram”}
- {Quoted: false, Content: “param1”}
- {Quoted: true, Content: “\“param2\””}
将指令行字元串分割為 CommandLineSegment[], 使用
CommandParser.SplitCommandLine(string str)
Argument
指令的參數, 可有名稱, 繼承
IArgument
, 當調用方法時, 将會被傳遞
ArgumentParser
下面是所有内置的
ArgumentParsers
-
ArguParser:
可将任何部分分析為一個
Argument
-
IdentifierArguParser:
可将一個辨別符部分分析為一個
. 對應的正規表達式是 “{A-Za-z_}{A-Za-z0-9_}*”Argument
-
StringArguParser:
可以将任何 Quoted(被雙引号包圍的) 部分分析為
Argument
-
FieldArguParser:
可以将像 name=value 的一個部分, 或者像 name= value 的兩個部分分析為一個
, 另外, 你可以指定分隔符, 預設分隔符是 ‘=’Argument
-
PropertyArguParser:
可以将像 -name value 的兩個部分分析為
, 并且你也可以指定 name 的起始字元串, 預設是 “-”Argument
ArgumentConverter
Here is all build-in
ArgumentConverter
:
-
ArguConverter:
不會做任何轉換而直接傳回源值的預設的
ArgumentConverter
-
BoolArguConverter:
幫助轉換到布爾值, 使用 bool.Parse 和 bool.TryParse
-
CharArguConverter:
幫助轉換到字元, 僅當字元串有唯一一個字元時, 傳回這個字元, 否則轉換失敗
- ByteArguConverter:
- ShortArguConverter:
- IntArguConverter:
- LongArguConverter:
- FloatArguConverter:
- DoubleArguConverter:
- BigIntArguConverter:
-
DecimalArguConverter:
上面提到的轉換器均傳回對應的數字類型, 并且它們都通過調用對應類型的
和Parse
方法實作轉換TryParse
-
EnumArguConverter<T>:
幫助轉換到枚舉類型, T 應該被指定為一個枚舉類型. 它可以從枚舉值的名稱或數字值來轉換
-
ForeachArguConverter<TConverter>:
幫助轉換到一個數組, 僅用于可變參數(使用
修飾),params
必須實作TConverter
接口, 每個值都将被指定的轉換器轉換, 最終得到一個對應類型的數組.IArgumentConverter
-
CharArrayArguConverter:
幫助轉換到字元數組, 它調用
來進行轉換.string.ToCharArray()
About ArgumentParser
Custom Parser:
定義自定義的
ArgumentParser
, 你需要遵守下面的規則:
- 實作
接口IArgumentParser
- 在分析完畢後, 引用參數
必須離開參數結果(IArgument)的區域, 例如, 在索引 3, 在你的自定義分析器中, 他将傳回結果 (結果被成功分析), 并且分析結果來自于兩個index
, 是以CommandLineSegment
必須是 5 (在 3 和 4 之外).index
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>
中, 所有方法重載均調用這兩個方法:
- T Convert(string argument);
- bool TryConverter(string argument, out T result);
是以如果繼承
ArgumentConverter<T>
, 你隻需要重寫這兩個方法.
Tips:
- 不要使用 new 表達式來建立一個
執行個體, 請使用ArgumentConverter
.ArgumentConverterManager.GetConverter<T>()
FAQ
- 當我調用
時, 某些分析器不能正常使用: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());