【问题标题】:Creating a Func<object[], object> Delegate from MethodInfo从 MethodInfo 创建一个 Func<object[], object> 委托
【发布时间】:2016-07-25 21:03:54
【问题描述】:

经过对 SO 的大量研究和搜索;我未能找到包含我的具体情况的答案。我希望为我的项目添加改装功能;目前我使用第 3 方 C# API,它可以将用特定解释语言(特别是这些脚本中的函数)编写的脚本转换为 C# 委托。

有没有办法将我从 3rd 方 API 获得的所有委托包装到一个通用的 Func 委托中?我的想法(在代码中)如下......

//The goal signature for all 'imported' delegates
public delegate object GenericSignature(object[] args);

//A fictional example...
public class Program
{
    public static void Main()
    {
        GenericSignature desiredFunc = GenerateFromArbitraryMethod(
               Program.FictionalArbitraryMethod);
        object retVal = desiredFunc(1, new object(), "If only this worked");
    }

    public static FictionalArbitraryMethod(int num, object stuff, string name) 
    { 
        //code from mod author would be here 
    }
}

//Attempt #1
//If my understanding about Delegate.CreateDelegate() is correct, 
//this will not work... 
public GenericSignature GenerateFromArbitraryMethod(Delegate d) {
    MethodInfo mInfo = d.Method;
    return (GenericSignature) Delegate.CreateDelegate(typeof(GenericSignature), mInfo);
}

//Attempt #2
//seems a bit... better?; I can do some validation, but how do I actually call the 
//function represented by MethodInfo since it's signature is arbitrary?
public GenericSignature GenerateFromArbitraryMethod(Delegate d) {
    MethodInfo mInfo = d.Method;

    return delegate(object[] args) {

        ParameterInfo[] pInfo = mInfo.GetParameters();
        if(args.length != pInfo.length) {
             throw new Exception("Argument count does not match");
        }

        for(int i = 0; i < args.length; i++) {
             if(pInfo[i].ParameterType != args[i].GetType()) {
                 throw new Exception("Incorrect Type for argument");
             } 
        }

        //At a loss of how to do the following; fake psuedo-code follows
        /*
        Foreach(object currentArg in arg) {
           d.AppendArgAndCast(currentArg); 
        }
        return d.Call();

        or...

        return d(EachOrUnpackAndCast(args));
        */

    };
}

如果语法有任何错误,我们深表歉意;我主要是想了解我想要实现的概念。一些附加说明:

  1. 基于来自here 的信息; Unity 支持 .NET 3.5 功能;所以我将使用的解决方案可以利用 .NET 3.5。

  2. 如果任何建议的解决方案由于大量使用反射而“缓慢/繁重”,则可以;只要我可以生成一个委托,我可以缓存它并多次调用(以摊销初始委托创建成本)

  3. Delegate.DynamicInvoke() 不符合我项目的性能要求。我的理解是每个 DynamicInvoke() 调用都使用反射 API。最好使用一次反射来创建更快的委托。

【问题讨论】:

  • 我不明白这个问题。给定一个委托实例和一个要传递的参数数组,为什么不能直接调用Delegate.DynamicInvoke() 并将数组传递给它呢?请尝试使您的代码示例更清晰,尤其是关于您遇到的具体问题以及您想要工作的内容。诸如“可能行不通”之类的评论没有帮助;要么有效,要么无效。不要让我们弄清楚它是否有效;自己尝试一下,如果它没有具体说明什么不起作用以及您需要什么帮助。
  • Delegate.DynamicInvoke() 对于我的用例来说太慢了;我会用这些信息更新问题;我忘了提这个。

标签: c# unity3d reflection delegates mono


【解决方案1】:

您需要编译自己的字节码以将每个参数从 object 转换为正确的类型。

如果您可以从 .Net 2 升级,Expression 让这一切变得非常简单。 如果没有,您将需要使用 ILGenerator,或者像 Sigil 这样的包装器。

【讨论】:

  • 我已经用更具体的信息更新了我的问题;该项目实际上是一个 Unity 项目。我相信项目设置确实以 .net 2.0 为目标,但 Intellisense 确实找到了“System.Linq.Expressions”进行导入;这是否意味着有希望?
  • @AMemberofDollars 我不知道表达式是否移植到 Mono 使用的版本。 Intelisense 完全取决于 .csproj 所针对的 .net 版本。您是否安装了适用于 Visual Studio 的 Unity 工具?您的项目属性说您的目标是什么版本(如果您无法打开项目属性,这意味着您确实安装了工具并且统一生成了 .csproj 文件,因此您不必担心它是错误的版本)。
  • @ScottChamberlain 嗨,斯科特;是的,我确实安装了“用于 VS 的 Unity 工具”,但我无法查看项目属性。一切都表明应该支持 LINQ 表达式。
  • @AMemberofDollars 然后试试看会发生什么。
  • @SLaks 我会看看我是否能弄清楚如何使用表达式来解决我的问题;如果我能想出点什么,我会将此问题标记为已完成。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-03-02
  • 2011-02-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多