我们正在开发一个系统,该系统将从tcp / ip流中读取命令,然后执行这些命令。命令由对对象的方法调用组成,该对象也由命令中的id标识。您可以将命令视为元素ID(寻址我们要在其上调用命令的元素)和命令ID(寻址应在元素上调用的方法)的信息。另外,还有一个问题,我们需要检查每个命令的某种权限以及如何执行此命令。 (应该在新的Thread
中启动,等等)
这样的命令调用看起来像一个例子:
class Callee
{
public void RegularCall(int command, parameters)
{
switch (command)
{
case 1: // Comand #1
// Check if the permissions allow this command to be called.
// Check if it should be outsourced to the ThreadPool and
// call it accordingly. +Other Checks.
// Finally execute command #1.
break;
case 2: // Comand #2
// Check if the permissions allow that command to be called.
// Check if it should be outsourced to the ThreadPool and
// call it accordingly. +Other Checks.
// Finally execute command #2.
break;
// Many more cases with various combinations of permissions and
// Other flags.
}
}
}
在某处:
static Dictionary<int, Callee> callees = new Dictionary<int, Callee>();
static void CallMethod(int elementId, int commandId, parameters)
{
callees[elementId].RegularCall(commandId, parameters);
}
但是,这种方法有点模糊:
我的第一个方法是使用反射,看起来应该是这样的:
class Callee
{
[Command(1)]
[Permissions(0b00111000)]
[UseThreadPool]
public void SpeakingNameForCommand1(parameters)
{
// Code for command #1.
}
[Command(2)]
[Permissions(0b00101011)]
public void SpeakingNameForCommand2(parameters)
{
// Code for command #2.
}
// Again, many more commands.
}
此代码必须已使用一些反射较重的代码初始化:
MethodInfo
。对收到的命令的调用如下所示,其中CommandInfo
是一个类,其中包含该调用所需的所有信息(MethodInfo
,在ThreadPool
中运行,权限... ):
static Dictionary<int, CommandInfo> commands = new Dictionary<int, CommandInfo>();
static void CallMethod(int elementId, int commandId)
{
CommandInfo ci = commands[commandId];
if (ci.Permissions != EVERYTHING_OK)
throw ...;
if (ci.UseThreadPool)
ThreadPool.Queue...(delegate { ci.MethodInfo.Invoke(callees[elementId], params); });
else
ci.MethodInfo.Invoke(callees[elementId], params);
}
当我进行微基准测试时,对MethodInfo.Invoke
的调用比直接调用慢大约100倍。 问题是:有没有一种更快的方法来调用这些“命令”方法,而又不会失去定义这些命令的调用方式的属性的优美性?
我还尝试从MethodInfo
派生一个委托。但是,这不能很好地工作,因为我需要能够在Callee
类的任何实例上调用该方法,并且不想为每个可能的element *命令为委托保留内存。 (将会有很多元素。)
仅需说明一下:MethodInfo.Invoke
比包含switch
/ case
语句的函数调用慢100倍。这不花时间遍历所有类,方法和属性,因为这些信息已经准备好了。
请不要让我知道其他瓶颈,例如网络。他们不是问题。而且,他们没有理由在代码的另一个位置使用慢速调用。谢谢。
答案 0 :(得分:2)
您可以使用开放委托,它比MethodInfo.Invoke
快十倍。您可以像这样从delegate
创建这样的MethodInfo
:
delegate void OpenCommandCall(Callee element, parameters);
OpenCommandCall occDelegate = (OpenCommandCall)Delegate.CreateDelegate(typeof(OpenCommandCall), methodInfo));
然后,您可以这样称呼此代表:
occDelegate.Invoke(callee, params);
在callee
是要调用该方法的元素的地方,methodInfo
是该方法的MethodInfo
,而parameters
是其他各种参数的占位符。 / p>
答案 1 :(得分:0)
也许您想尝试一下ObjectMethodExecutor
根据Hanselman:
如果您需要通过反射在某个类型上调用一个方法,并且该方法可能是异步的,我们将在ASP.NET Core代码库中的每个地方都使用一个高度优化和灵活的助手,称为ObjectMethodExecutor。< / p>
团队在MVC中使用此代码来调用您的控制器方法。他们在SignalR中使用此代码来调用您的集线器方法。它处理异步和同步方法。它还处理定制的等待和F#异步工作流程