我正在项目中实现类似解释器的功能。目标是允许此库的用户调用Invoke(command, param1, param2, param3...)
之类的东西来调用不同的命令。每个命令都是该类的方法。
我目前的实施方式如下:
class MyTest: IInvokable {
public void Command1(string pa)
{
throw new NotImplementedException();
}
public int Command2(string pa, int a)
{
throw new NotImplementedException();
}
public string Command3()
{
throw new NotImplementedException();
}
public CommandResult Invoke(string cmd, params object[] p)
{
switch(cmd)
{
case "Command1":
case "Command1Alias":
return new CommandResult(this.Command1(p[0].ToString()));
break;
case "Command2":
*** omitted ***
}
}
}
巨人switch-case
对我来说真的很傻。我看了Command Pattern,但不知道它是否适用于此。有什么建议让代码更好吗?
答案 0 :(得分:1)
首先,定义两个属性来标识允许调用的方法,以及设置方法别名的能力:
public class CommandAttribute : Attribute
{
}
[System.AttributeUsage(validOn: System.AttributeTargets.Method, AllowMultiple = true)]
public class CommandAliasAttribute : Attribute
{
public CommandAliasAttribute(string alias)
{
Alias = alias;
}
public string Alias { get;}
}
现在我们可以使用它来标记可调用的方法:
public class Test
{
[Command]
[CommandAlias("Method1Alias")]
public void Method1()
{
System.Console.WriteLine("Method1");
}
[Command]
[CommandAlias("Method2Alias")]
public void Method2()
{
System.Console.WriteLine("Method2");
}
public void NonInvokableMethod()
{
System.Console.WriteLine("NonInvokableMethod");
}
}
最后,让我们添加调用方法:
public class Test
{
[Command]
[CommandAlias("Method1Alias")]
public void Method1()
{
System.Console.WriteLine("Method1");
}
[Command]
[CommandAlias("Method2Alias")]
public void Method2()
{
System.Console.WriteLine("Method2");
}
public void NonInvokableMethod()
{
System.Console.WriteLine("NonInvokableMethod");
}
public object Invoke(string cmd)
{
var type = GetType();
var methodinfo = type.GetMethods().SingleOrDefault(x =>
x.GetCustomAttribute(typeof(CommandAttribute)) != null //Only allow methods with the Command attribute
&&
(
x.Name == cmd //Match method name
|| x.GetCustomAttributes(typeof(CommandAliasAttribute)) //Match alias
.Select(attr => attr as CommandAliasAttribute) //type cast to CommandAlias
.Any(attr => attr.Alias == cmd)
));
if (methodinfo == null)
throw new InvalidOperationException($"No method named or aliased \"{cmd}\" was found.");
var ret = methodinfo.Invoke(this, new object[0]);
return ret;
}
}
测试方法:
void Main()
{
var test = new Test();
test.Invoke("Method1");
test.Invoke("Method1Alias");
try
{
test.Invoke("MethodX");
}
catch (Exception e)
{
System.Console.WriteLine(e.Message);
}
try
{
test.Invoke("NonInvokableMethod");
}
catch (Exception e)
{
System.Console.WriteLine(e.Message);
}
}
此示例不包括参数的使用,但我认为您可以弄清楚如何调整invoke方法以支持它。请记住,例如,如果您希望从命令提示符调用方法,则需要将参数从string转换为各自的参数类型。否则,在调用方法时会出现异常。