从MethodInfo创建一个Func <object [],object =“”>委托

时间:2016-07-25 21:03:55

标签: c# unity3d reflection delegates mono

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

有没有办法将我从第三方API获得的所有代理包装到一个通用的Func Delegate中?我的想法(在代码中)遵循......

//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。最好使用反射一次来创建更快的委托。

1 个答案:

答案 0 :(得分:1)

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

如果您可以从.Net 2升级,Expression会让这很容易。 如果没有,您将需要使用ILGenerator或Sigil等包装器。