Consider the following repro code distilled from a customer-affecting EF issue:
```c#
using System;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
namespace StackSpiller
{
internal class Program
{
public static void Main(string[] args)
{
var guidToStringMethodInfo
= typeof(Guid)
.GetTypeInfo().GetDeclaredMethods("ToString")
.Single(m => !m.GetParameters().Any());
var customerCtorInfo
= typeof(Baz)
.GetTypeInfo().DeclaredConstructors.Single();
var guidConstant = Expression.Constant(Guid.NewGuid());
var goodExpressionTree
= Expression.Lambda<Func<Baz>>(
Expression.New(
customerCtorInfo,
Expression.Call(
Expression.TryCatch(
guidConstant,
Expression.Catch(typeof(Exception), guidConstant)),
guidToStringMethodInfo),
Expression.Constant("Foo")));
var goodLambda = goodExpressionTree.Compile();
Console.WriteLine(goodLambda());
var badExpressionTree
= Expression.Lambda<Func<Baz>>(
Expression.New(
customerCtorInfo,
// ctor arguments are re-ordered
Expression.Constant("Foo"),
Expression.Call(
Expression.TryCatch(
guidConstant,
Expression.Catch(typeof(Exception), guidConstant)),
guidToStringMethodInfo)));
var badLambda = badExpressionTree.Compile();
Console.WriteLine(badLambda());
}
private class Baz
{
public Baz(string a, string b)
{
}
}
}
}
which produces:
StackSpiller.Program+Baz
Unhandled Exception: System.NotSupportedException: TryExpression is not supported as a child expression when accessing a m
ember on type 'System.Guid' because it is a value type. Construct the tree so the TryExpression is not nested inside of th
is expression.
at System.Linq.Expressions.Compiler.StackSpiller.RequireNotRefInstance(Expression instance)
at System.Linq.Expressions.Compiler.StackSpiller.RewriteMethodCallExpression(Expression expr, Stack stack)
at System.Linq.Expressions.Compiler.StackSpiller.RewriteExpression(Expression node, Stack stack)
at System.Linq.Expressions.Compiler.StackSpiller.ChildRewriter.Add(Expression node)
at System.Linq.Expressions.Compiler.StackSpiller.ChildRewriter.AddArguments(IArgumentProvider expressions)
at System.Linq.Expressions.Compiler.StackSpiller.RewriteNewExpression(Expression expr, Stack stack)
at System.Linq.Expressions.Compiler.StackSpiller.RewriteExpression(Expression node, Stack stack)
at System.Linq.Expressions.Compiler.StackSpiller.RewriteExpressionFreeTemps(Expression expression, Stack stack)
at System.Linq.Expressions.Compiler.StackSpiller.Rewrite[T](Expression1 lambda)
at System.Linq.Expressions.Expression1.Accept(StackSpiller spiller)
at System.Linq.Expressions.Compiler.LambdaCompiler.Compile(LambdaExpression lambda)
at System.Linq.Expressions.Expression1.Compile(Boolean preferInterpretation)
at System.Linq.Expressions.Expression1.Compile()
at StackSpiller.Program.Main(String[] args) in C:\Dev\github\StackSpiller\Program.cs:line 52
```
The only difference in the two expressions is the order in which the constructor args are passed when creating the NewExpression.
Is this a bug?
It's a limitation being addressed in https://github.com/dotnet/corefx/pull/13126. Glad another real-world case was reported :-).
Closing 馃槃
The underlying limitation has also been lifted now, so future versions of .NET Standard (at this point 2.0 over in corefx) will no longer require you to work around uses of TryExpression in various places.
Most helpful comment
The underlying limitation has also been lifted now, so future versions of .NET Standard (at this point 2.0 over in
corefx) will no longer require you to work around uses ofTryExpressionin various places.