.net - .Net 3.5 中通过字符串名称调用方法的最快方法是什么?

标签 .net performance .net-3.5

所以显而易见的方法是..

var handler = GetType().GetMethod(methodName, BindingFlags.NonPublic |
                                              BindingFlags.Instance);

handler.Invoke(this, new object[] {e});

而且我可以添加缓存以保留这些方法,但我想知道是否有完全不同且更快的方法?

最佳答案

最快的方法是缓存一个类型化的委托(delegate);如果您知道签名始终是:

void PersonInstance.MethodName(string s);

然后你可以创建一个 Action<Person,string>通过 Delegate.CreateDelegate:
var action = (Action<Person,string>)Delegate.CreateDelegate(
    typeof(Action<Person,string>), method);

然后可以根据名称缓存它,并调用为:
action(personInstance, value);

注意这里的缓存很关键;定位方法和准备类型委托(delegate)的反射(reflection)并非易事。

如果签名是不可预测的,则变得更加困难,因为 DynamicInvoke 相对较慢。最快的方法是使用 DynamicMethod 和 ILGenerator 编写一个 shim 方法(即时),该方法采用 object[] 作为参数并解包并将其强制转换以匹配签名 - 然后您可以存储 Action<object, object[]>Func<object,object[],object> .然而,这是一个高级主题。如果真的需要,我可以提供一个例子。本质上写(在运行时):
void DummyMethod(object target, object[] args) {
    ((Person)target).MethodName((int)args[0],(string)args[1]);
}

这是一个这样做的示例(注意:它目前不处理 ref/out args,可能还有其他一些场景 - 我已经将事物的“缓存”方面作为练习留给读者):
using System;
using System.Reflection;
using System.Reflection.Emit;

class Program
{
    static void Main()
    {
        var method = typeof(Foo).GetMethod("Bar");
        var func = Wrap(method);
        object[] args = { 123, "abc"};
        var foo = new Foo();
        object result = func(foo, args);
    }

    static Func<object, object[], object> Wrap(MethodInfo method)
    {
        var dm = new DynamicMethod(method.Name, typeof(object), new Type[] {
            typeof(object), typeof(object[])
        }, method.DeclaringType, true);
        var il = dm.GetILGenerator();

        if (!method.IsStatic)
        {
            il.Emit(OpCodes.Ldarg_0);
            il.Emit(OpCodes.Unbox_Any, method.DeclaringType);
        }
        var parameters = method.GetParameters();
        for (int i = 0; i < parameters.Length; i++)
        {
            il.Emit(OpCodes.Ldarg_1);
            il.Emit(OpCodes.Ldc_I4, i);
            il.Emit(OpCodes.Ldelem_Ref);
            il.Emit(OpCodes.Unbox_Any, parameters[i].ParameterType);
        }
        il.EmitCall(method.IsStatic || method.DeclaringType.IsValueType ?
            OpCodes.Call : OpCodes.Callvirt, method, null);
        if (method.ReturnType == null || method.ReturnType == typeof(void))
        {
            il.Emit(OpCodes.Ldnull);
        }
        else if (method.ReturnType.IsValueType)
        {
            il.Emit(OpCodes.Box, method.ReturnType);
        }
        il.Emit(OpCodes.Ret);
        return (Func<object, object[], object>)dm.CreateDelegate(typeof(Func<object, object[], object>));
    }
}

public class Foo
{
    public string Bar(int x, string y)
    {
        return x + y;
    }
}

关于.net - .Net 3.5 中通过字符串名称调用方法的最快方法是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7531297/

相关文章:

c# - 如何将目录标记为 "in use"以使其无法删除或重命名?

.net - Web 安装项目 - 获取当前机器名称

java - 在 Java 中,通过 getter 引用字段与通过变量引用字段之间是否存在性能差异?

java - 为什么^(?: x + y){5} $的性能比^ x + yx + yx + yx + yx + y $慢

performance - 分析 OpenGL 应用程序 - 当驱动程序阻塞 CPU 端时

c# - 是否可以通用地实现这个接口(interface),以便它只能传递一个类型参数?

c# - asp.net core web.api 应用程序无法启动

c# - 标签助手未在 ASP.NET Core 2 中处理

c# - 不允许使用默认参数说明符

c# - 关闭 FileStream 会关闭 StreamReader 吗?