注意:Func<Tn,T>
=可以是任意数量的类型
我最近选择了一个我已经工作了一段时间的项目并且正在审核代码。在我休息之前,我因为一种方法的实施而变得更加糟糕,所以我花了大约2天的时间来努力使它变得更好。我正在尝试动态创建Func<>
,其中包含在运行时已知的泛型类型参数count,type和return类型。
我现在使用的当前代码块是这个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));
哪个有效......但是......我认为可以更加动态地完成它以包含所有方法。
答案 0 :(得分:0)
代码:
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);
}
以下是我用来获取委托/ func类型的代码
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);
}