是否可以在 C# 中调用动态对象

本文关键字:调用 动态 对象 是否 | 更新日期: 2023-09-27 18:31:29

我有一个可调用的"动态"类型的对象。我正在尝试实现一个函数,该函数将使用一组参数在运行时动态调用对象。如果我知道编译时的参数数量,调用它很容易:

Object StaticInvoke(dynamic func, Object[] args) {
    // arguments are explicitly unwrapped and bound to the invokation
    // requiring that we know the number at compile time
    return func(args[0], args[1], ...); 
}

但是,这并不能实现我想要的,因为 args 数组的长度可能是可变的。我想不出支持任意数量的参数的方法。我想出的最接近的是:

static Object Invoke(dynamic func, Object[] args)
{
    // not sure what to put here
    switch(args.Length)
    {
        case 0:
            return func();
        case 1:
            return func(args[0]);
        case 2:
            return func(args[0], args[1]);
        ...
        default:
            throw new NotSupportedException();
    }
}

这将限制我可能通过的参数数量。我想我可以忍受这种限制,但感觉我正在尝试做的事情应该是可能的。

我基本上是在尝试在 C# 中实现 javascript "apply" 函数。有没有更简单的方法来完成我想要做的事情?我觉得我错过了一些明显的东西。

是否可以在 C# 中调用动态对象

开源 apache 许可的 ImpromptuInterface(在 nuget 上)有一个静态方法 Impromptu.Invoke 来做到这一点。您可以查看实现,虽然它处理任意数量的参数,但它也确实可以正常工作,例如提供动态描述命名参数并调用它们的机制。

根据您的使用情况,您的开关案例想法实际上可能是要走的路,因为它应该既简单又快速。

对于开关大小写,N 是您支持的最大参数数,C# 编译器将创建 N+1 个调用站点,它只是静态地知道它们的位置。即兴将调用 dlr API,就像编译器一样,但它会将调用站点存储在哈希表中,这将增加查找时间(虽然还不错)。

dlr api 还需要一个委托,该委托的签名与您调用的数字或参数相匹配,编译器将再次确保您静态拥有 N+1 个委托,而 Impromptu 将使用 17 个内置 Func<> 在开关情况下,然后根据需要开始发出新委托,生成是一次性的沉重成本,然后为后续调用添加更多哈希表查找。

编辑:这不是一个答案 - 把它留在这里让其他人知道它不太可能是@Mark寻找的。

对于常规对象,您将使用MethodBase.InvokeMethod

 MethodInfo magicMethod = magicType.GetMethod("ItsMagic");
 object magicValue = magicMethod.Invoke(magicClassObject, new object[]{100});