从 MethodInfo 创建 Func<object[], object> 委托
Creating a Func<object[], object> Delegate from MethodInfo
经过对 SO 的大量研究和搜索;我未能找到包含我的具体情况的答案。我希望为我的项目添加修改功能;目前我使用第 3 方 C# API,它可以将以特定解释语言编写的脚本(特别是这些脚本中的函数)转换为 C# 委托。
有没有办法将我从第 3 方 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));
*/
};
}
如有语法错误,敬请谅解;我主要是想弄清楚我要实现的目标的概念。一些补充说明:
基于 here 的信息; Unity 支持.NET 3.5 特性;所以我将使用的解决方案最多可以利用 .NET 3.5。
由于大量使用反射,如果任何建议的解决方案是 'slow/heavy' 也没关系;只要我可以生成一个委托,我可以缓存它并调用很多次(以分摊初始委托创建成本)
Delegate.DynamicInvoke() 不符合我项目的性能要求。我的理解是每个 DynamicInvoke() 调用都使用反射 API。最好使用一次反射来创建更快的委托。
您需要编译自己的字节码以将每个参数从 object
转换为正确的类型。
如果您可以从 .Net 2 升级,Expression
将使这变得非常容易。
如果没有,您将需要使用 ILGenerator 或 Sigil 等包装器。
经过对 SO 的大量研究和搜索;我未能找到包含我的具体情况的答案。我希望为我的项目添加修改功能;目前我使用第 3 方 C# API,它可以将以特定解释语言编写的脚本(特别是这些脚本中的函数)转换为 C# 委托。
有没有办法将我从第 3 方 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));
*/
};
}
如有语法错误,敬请谅解;我主要是想弄清楚我要实现的目标的概念。一些补充说明:
基于 here 的信息; Unity 支持.NET 3.5 特性;所以我将使用的解决方案最多可以利用 .NET 3.5。
由于大量使用反射,如果任何建议的解决方案是 'slow/heavy' 也没关系;只要我可以生成一个委托,我可以缓存它并调用很多次(以分摊初始委托创建成本)
Delegate.DynamicInvoke() 不符合我项目的性能要求。我的理解是每个 DynamicInvoke() 调用都使用反射 API。最好使用一次反射来创建更快的委托。
您需要编译自己的字节码以将每个参数从 object
转换为正确的类型。
如果您可以从 .Net 2 升级,Expression
将使这变得非常容易。
如果没有,您将需要使用 ILGenerator 或 Sigil 等包装器。