ViRuSTriNiTy
ViRuSTriNiTy

Reputation: 5155

Why is my LINQ Expression with multiple parameters not compiling?

I want to extend the LINQ expression (DoSomething)

using LinqKit; // for System.Linq.Expressions.Expression<>.Invoke()

public class Expressions
{
  public static System.Linq.Expressions.Expression<
    System.Func<int, int, int, int, bool>>
      DoSomething =
        (a, b, c, d) => false;
}

public class ExpressionTester
{
  public ExpressionTester()
  {
    Expressions.DoSomething.Invoke(1, 2, 3, 4);
  }
}

with an additional parameter but it does not compile:

public class Expressions
{
  public static System.Linq.Expressions.Expression<
    System.Func<int, int, int, int, int, bool>>
      DoSomething =
        (a, b, c, d, e) => false;
}

public class ExpressionTester
{
  public ExpressionTester()
  {
    Expressions.DoSomething.Invoke(1, 2, 3, 4, 5);
  }
}

The best overloaded method match for 'System.Linq.Expressions.Expression.Invoke(System.Linq.Expressions.Expression, params System.Linq.Expressions.Expression[])' has some invalid arguments
error CS1503: Argument 1: cannot convert from 'int' to 'System.Linq.Expressions.Expression'
error CS1503: Argument 2: cannot convert from 'int' to 'System.Linq.Expressions.Expression'
error CS1503: Argument 3: cannot convert from 'int' to 'System.Linq.Expressions.Expression'
error CS1503: Argument 4: cannot convert from 'int' to 'System.Linq.Expressions.Expression'
error CS1503: Argument 5: cannot convert from 'int' to 'System.Linq.Expressions.Expression'

Is there an undocumented limitation to the number of parameters?

:edit

Thanks to the answer of an unknown author that deleted its answer 10 seconds later i see that LinqKit is compiled with .NET 3.5 whereas this caused the limitation of System.Func<> to 4 parameters.

:edit2

The suggested Compile().Invoke() workaround is not working in all cases in connection with queries (which i need). Thus i created a fork from the LINQKit project and added some code to support up to 16 parameters:

https://github.com/ViRuSTriNiTy/LINQKit/commit/bcca71978ef3fbb988d242463adfbc4e9cd42565

Upvotes: 2

Views: 1670

Answers (3)

D Stanley
D Stanley

Reputation: 152566

When you add a fifth parameter, you're binding to a different Invoke that the one in LinqKit:

public static TResult Invoke<T1, T2, T3, T4, TResult> (
    this Expression<Func<T1, T2, T3, T4, TResult>> expr, T1 arg1, T2 arg2, T3 arg3, T4 arg4)
{
    return expr.Compile ().Invoke (arg1, arg2, arg3, arg4);
}

Note that there's not one with 5 arguments, so you end up binding to Expression.Invoke, which takes a parameter array of Expressions:

public static InvocationExpression Invoke(Expression expression, params Expression[] arguments) {
    return Invoke(expression, (IEnumerable<Expression>)arguments);
}

Luckily, you can replicate the implementation from LinqKit by just calling Compile() on the expression to turn it into a delegate:

public class ExpressionTester
{
  public ExpressionTester()
  {
    Expressions.DoSomething.Compile().Invoke(1, 2, 3, 4, 5);
  }
}

Upvotes: 4

DLeh
DLeh

Reputation: 24395

You could just call .Compile().Invoke() instead. This code compiles:

public class Expressions
{
    public static System.Linq.Expressions.Expression<
      System.Func<int, int, int, int, int, bool>>
        DoSomething =
          (a, b, c, d, e) => false;
}

public class ExpressionTester
{
    public ExpressionTester()
    {
        Expressions.DoSomething.Compile().Invoke(1, 2, 3, 4, 5);
    }
}

Upvotes: 2

xanatos
xanatos

Reputation: 111860

The LinqKit 1.1.2 I've found on nuget (and on github) supports up to four parameters for the Invoke...

public static TResult Invoke<T1, T2, T3, T4, TResult>(this Expression<Func<T1, T2, T3, T4, TResult>> expr, T1 arg1, T2 arg2, T3 arg3, T4 arg4)
{
    return expr.Compile()(arg1, arg2, arg3, arg4);
}

It is trivial to do it for 5 parameters based on the one with 4.

public static TResult Invoke<T1, T2, T3, T4, T5, TResult>(this Expression<Func<T1, T2, T3, T4, T5, TResult>> expr, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5)
{
    return expr.Compile()(arg1, arg2, arg3, arg4, arg5);
}

Upvotes: 3

Related Questions