[英]How can I write a method that accepts a lambda expression where the number of parameters to the lambda expression is unknown?
我正在尝试编写一种接受lambda表达式的方法。 此lambda表达式的输入参数的数量在我的代码中将有所不同。 输入参数的数量将确定方法主体中发生的情况。
伪代码如下:
private void foo(Expression e)
{
// I don't know what parameter type foo should accept -- please suggest!
double a, b, c;
int count = e.NumberOfArguments;
double[] args;
if(count == 1) args = new[]{a};
else if(count == 2) args = new[]{ a, b };
... and so on...
e.Invoke(args);
}
private void goo()
{
// called as follows:
foo(x => true);
foo((x,y) => true);
foo((x,y,z) => true);
}
我真的不知道foo应该接受哪个对象作为参数(我猜可能是一个Expression?),而且我也不确定如何获取lambda表达式中的参数数量以及如何调用它。
另外,如果可以通过传递具有可变数量的元素的数组来调用e,则将是一个好处。
其他内容:
我有一个时间序列对象。 当使用N个参数调用foo时,我希望将时间序列与其一阶,二阶,三阶...(N-1)次导数一起使用以生成结果(例如bool)。 在某些情况下,我只需要使用时间序列本身,在这种情况下,我将只提供一个参数。 在其他情况下,我希望使用时间序列生成结果,它是一阶导数也是二阶导数-在这种情况下,我将提供3个参数。 等等...
我希望这更有意义。 我也愿意以更优雅的方式来实现此要求。
好了,它可以编译并运行,但是我不确定我是否希望在我的代码库中使用它:
using System;
using System.Linq.Expressions;
namespace ConsoleApplication1
{
internal sealed class Program
{
private static void Main(string[] args)
{
goo();
Console.ReadLine();
}
private static void foo(LambdaExpression e)
{
double a, b, c;
a = 1.0;
b = 1.0;
c = 1.0;
bool result = false;
int count = e.Parameters.Count;
if (count == 1)
{
result = (bool)e.Compile().DynamicInvoke(a);
}
else if (count == 2)
{
result = (bool)e.Compile().DynamicInvoke(a,b);
}
Console.WriteLine(result);
}
private static void goo()
{
foo((Expression<Func<double, bool>>) (x => true));
foo((Expression<Func<double, double, bool>>) ((x, y) => true));
foo((Expression<Func<double, double, double, bool>>) ((x, y, z) => true));
}
}
}
而且我也不确定是否会解决您的实际问题。 (此外,请插入有关一般完全没有错误检查的警告,等等)
基于Damien的出色回答,我将重构代码以使其更加有用。
static void Main(string[] args)
{
TestFoo();
}
private static Tuple<bool, Exception> Foo<T>(LambdaExpression expression, out T result, params object[] parameters)
{
bool succesful = false;
result=default(T);
Exception invokeException = null;
if (expression.Parameters.Count == parameters.Length)
{
try
{
result = (T)expression.Compile().DynamicInvoke(parameters);
succesful = true;
}
catch (Exception e)
{
invokeException = e;
}
}
return new Tuple<bool, Exception>(succesful, invokeException);
}
private static void TestFoo()
{
bool result;
double sum;
var succesful = Foo((Expression<Func<bool>>)(() => true), out result);
Debug.Assert(succesful.Item1);
Debug.Assert(result);
Debug.Assert(succesful.Item2 == null);
succesful = Foo((Expression<Func<double, bool>>)(x => x == 1.0), out result, 1.0);
Debug.Assert(succesful.Item1);
Debug.Assert(result);
Debug.Assert(succesful.Item2 == null);
succesful = Foo((Expression<Func<double, double, double>>)((x, y) => x + y), out sum, 2.0, 3.0);
Debug.Assert(succesful.Item1);
Debug.Assert(sum == 5);
Debug.Assert(succesful.Item2 == null);
succesful = Foo((Expression<Func<double, double, double>>)((x, y) => x + y), out sum, 2.0, new object());
Debug.Assert(!succesful.Item1);
Debug.Assert(succesful.Item2 is ArgumentException);
}
这应该工作得很好。
我认为,使其易于维护,使foo
重载更为有意义。 到那时,您可以轻松地引入用于处理参数数量的自定义逻辑,因为您确切知道自己有多少个参数。
// forward to main implementation
private void foo(Func<bool> e)
{
foo((a, b, c) => e());
}
// forward to main implementation
private void foo(Func<double, bool> e)
{
foo((a, b, c) => e(a));
}
// forward to main implementation
private void foo(Func<double, double, bool> e)
{
foo((a, b, c) => e(a, b));
}
// the main implementation
private void foo(Func<double, double, double, bool> e)
{
double a, b, c;
...
e(a, b, c);
}
private void goo()
{
foo(() => true);
foo(x => true);
foo((x,y) => true);
foo((x,y,z) => true);
}
请注意,由于您的问题是关于直接调用它(而不是例如将其传递给LINQ提供程序),因此我在这里不使用Expression
类型,但是对于Expression<Func<bool>>
, Expression<Func<double, bool>>
,...重载。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.