簡體   English   中英

如何編寫一個接受lambda表達式的方法,其中lambda表達式的參數數量未知?

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM