37

When I am trying to compile the following code:

var post = iPostService.GetAll().Select(x => (x.Title, x.Author));

I get the compiler error: 'An expression tree may not contain a tuple literal.'

So I also tried this:

var post = iPostService.GetAll().
                    Select(x => new ValueTuple<string, string>(x.Title, x.Author))

The result is runtime error:'Cannot resolve method Void .ctor(System.String, System.String) because the declaring type of the method handle System.ValueTuple`2[T1,T2] is generic. Explicitly provide the declaring type to GetMethodFromHandle.'

I googled to find out the solution to this problem but nothing really helpful.

Any help really appreciated.

Thanks

Tan Sang
  • 1,897
  • 1
  • 16
  • 28
  • 1
    The original issue is tracked by [Expression trees support for tuples. #12897](https://github.com/dotnet/roslyn/issues/12897). But looks like you can't use `ValueTuple` in any way inside compile time expression, so I'm afraid there is no solution / workaround at this time. – Ivan Stoev Jan 07 '18 at 15:04
  • This works now with EF Core, – quitprog Nov 15 '22 at 12:20

2 Answers2

31

It works for me, create a tuple first and convert it to a ValueTuple:

var post = iPostService.GetAll().
           Select(x => new Tuple<string, string>(x.Title, x.Author).ToValueTuple())
Steven Chou
  • 1,504
  • 2
  • 21
  • 43
  • 2
    Fantastic answer! This problem was preventing me to mock my automapper method CreateMap (where I was using a tupple). More info on why this problem ("An expression tree may not contain a tuple literal") exists here: https://www.damirscorner.com/blog/posts/20181207-NoSupportForTuplesInExpressionTrees.html – Luis Gouveia Mar 29 '21 at 20:09
17

Finally, I found out what wrong with my code:

  • I am using deferred execution so data won't load from the database when the constructor executed.
  • The solution is to add conversion operators before creating instance command.

Hope it works with your code.

Tan Sang
  • 1,897
  • 1
  • 16
  • 28
  • 6
    In my case, to deal with deferred execution, I just added .AsEnumerable() before my Select() statement – Jack Dec 03 '20 at 22:10
  • 3
    As @jack says. adding AsEnumerable() before the Select() projection makes the lambda internal to it a delegate function instead of an expression tree, which DOES allow tuple literals – PillowMetal Jul 19 '21 at 21:10
  • Yep can confirm, I didn't realize my Select was before an EF-materializing AsEnumerable, ToArray, etc., and so it seems Tuples are not allowed to be used for generating expression trees for generating SQL, much like how the null-coalescing operator isn't. Simple solution is to materialize first. – nh43de Aug 27 '23 at 15:00