动态构建函数与动态主体使用表达式
本文关键字:动态 主体 表达式 构建 函数 Tn | 更新日期: 2023-09-27 18:08:26
注意:Func<Tn,T>
=可以是任意类型
我最近捡起了一个我已经做了一段时间的项目,正在审核代码。在我休息之前,我被一个方法的执行激怒了,所以我花了大约2天的时间来改进它。我试图动态地创建一个Func<>
与泛型类型参数计数,类型和返回类型在运行时已知。
我现在使用的当前代码块是这个switch语句:(抱歉格式)
foreach (var member in LinkedDocument.GetType()
.GetMethods()
.Where(
method =>
method.GetCustomAttributes(
typeof(ScriptingMethodAttribute), true)
.Length != 0))
{
Delegate method;
switch (member.GetParameters()
.Count())
{
case 0:
method = new Func<dynamic>(() => member.Invoke(LinkedDocument, null));
break;
case 1:
method = new Func<object, dynamic>(
param => member.Invoke(
LinkedDocument, new[]
{
param
}));
break;
case 2:
method =
new Func<object, object, dynamic>(
(param1, param2) => member.Invoke(
LinkedDocument, new[]
{
param1,
param2
}));
break;
case 3:
method =
new Func<object, object, object, dynamic>(
(param1, param2, param3) => member.Invoke(
LinkedDocument, new[]
{
param1,
param2,
param3
}));
break;
case 4:
method =
new Func<object, object, object, object, dynamic>(
(param1, param2, param3, param4) => member.Invoke(
LinkedDocument, new[]
{
param1,
param2,
param3,
param4
}));
break;
default:
throw new NotImplementedException();
}
initalScope.Add(member.Name.ToLower(), method);
}我试图使用表达式树的动态构建它,我正在阅读教程,但我只是没有得到它。我看到的所有例子都使用静态类型exp: Func<object, object, dynamic>
。
我不想做这个。我想根据方法参数计数动态地构建它。这是我到目前为止得到的……
var assem = System.Reflection.Assembly.GetAssembly(typeof(Func<object>));
var type = assem.GetType(string.Format("Func`{0}", obj.GetParameters().Count()));
var typeArr = obj.GetParameters().Select(param => param.ParameterType).ToList();
typeArr.Add(obj.ReturnType);
var ctrInfo = type.GetConstructor(typeArr.ToArray());
var expType = Expression.New(type);
,我认为这是Expression
发挥作用的地方。但是我真的很难理解教程以及如何将解决方案集成到我的问题中。
注意:我不想解决我的具体问题,只是一些指导会很好。
谢谢你的帮助。
:
在重新考虑我的实现时,我记得为什么我不想使用object[]
。
我仍然需要这样写:
switch (member.GetParameters().Count())
{
case 0:
method = new Func<dynamic>(() => member.Invoke(LinkedDocument, null));
break;
case 1:
method = new Func<object, dynamic>(param => member.Invoke(LinkedDocument, new[] { param }));
break;
default:
method = new Func<object[], dynamic>(
param => member.Invoke(
LinkedDocument, param));
break;
}
或:
var paramCount = member.GetParameters().Count();
if(paramCount == 0)
method = new Func<dynamic>(() => member.Invoke(LinkedDocument, null));
else if(paramCount == 1)
method = new Func<object, dynamic>(param => member.Invoke(LinkedDocument, new[] { param }));
else
method = new Func<object[], dynamic>(
param => member.Invoke(
LinkedDocument, param));
工作……但是…我只是觉得可以更动态地包含所有的方法
- 获取ParameterExpressions的列表。我通过调用GetParameters,然后使用Select和ToList从ParameterInfo转换为ParameterExpression
- 创建一个表达式,用参数调用你的方法
- 确定委托类型。它看起来像你有一个工作方法,但我也包括我的代码下面。
- 创建一个lambda表达式,传递你的委托类型、调用方法的表达式(这是lambda表达式的主体)和你的参数。
- 设置"method"等于lambda表达式的编译版本。
- 对委托做任何你想做的事。
foreach (var member in LinkedDocument.GetType()
.GetMethods()
.Where(
method =>
method.GetCustomAttributes(
typeof(ScriptingMethodAttribute), true)
.Length != 0))
{
var parameters = member.GetParameters().Select(v => Expression.Parameter(v.ParameterType, v.Name)).ToList();
var caller = Expression.Call(member, parameters);
var delegateType = GetFuncType(member.GetParameters().Select(v => v.ParameterType).ToArray(), member.ReturnType);
var methodLambda = Expression.Lambda(delegateType, caller, parameters);
Delegate method = methodLambda.Compile();
initalScope.Add(member.Name.ToLower(), method);
}
下面是我用来获取委托/函数类型
的代码public static Type[] _baseFuncTypes = new Type[] { typeof(Func<>), typeof(Func<,>), typeof(Func<,,>), typeof(Func<,,,>), typeof(Func<,,,,>), typeof(Func<,,,,,>), typeof(Func<,,,,,,>), typeof(Func<,,,,,,,>), typeof(Func<,,,,,,,,>) };
private static Type GetFuncType(Type[] parameterTypes, Type returnType)
{
Array.Resize(ref parameterTypes, parameterTypes.Length + 1);
parameterTypes[parameterTypes.Length - 1] = returnType;
return _baseFuncTypes[parameterTypes.Length - 1].MakeGenericType(parameterTypes);
}