diff --git a/src/Framework/Framework/Compilation/Binding/ExpressionNullPropagationVisitor.cs b/src/Framework/Framework/Compilation/Binding/ExpressionNullPropagationVisitor.cs index a33c85b1e..b9248fc51 100644 --- a/src/Framework/Framework/Compilation/Binding/ExpressionNullPropagationVisitor.cs +++ b/src/Framework/Framework/Compilation/Binding/ExpressionNullPropagationVisitor.cs @@ -206,15 +206,11 @@ protected Expression UnwrapNullableType(Expression expression, Type expectedType return expression; else if (expression.Type == typeof(Nullable<>).MakeGenericType(expectedType)) { - var tmp = Expression.Parameter(expression.Type); - var nreCtor = typeof(NullReferenceException).GetConstructor(new [] { typeof(string) })!; - return Expression.Block(new [] { tmp }, - Expression.Assign(tmp, expression), - Expression.Condition( - Expression.Property(tmp, "HasValue"), - Expression.Property(tmp, "Value"), - Expression.Throw(Expression.New(nreCtor, Expression.Constant($"Binding expression '{formattedExpression}' of type '{expectedType}' has evaluated to null.")), expectedType) - ) + return Expression.Call( + ThrowHelpers.UnwrapNullableMethod.MakeGenericMethod(expectedType), + expression, + Expression.Constant(formattedExpression, typeof(string)), + Expression.Constant(expectedType.FullName, typeof(string)) ); } else @@ -283,5 +279,17 @@ public static Expression PropagateNulls(Expression expr, Func var v = new ExpressionNullPropagationVisitor(canBeNull); return v.Visit(expr); } + + + internal class ThrowHelpers + { + public static readonly MethodInfo ThrowNullReferenceMethod = typeof(ThrowHelpers).GetMethod(nameof(ThrowNullReference))!; + public static T ThrowNullReference(string expression, string type) => + throw new NullReferenceException($"Binding expression '{expression}' of type '{type}' has evaluated to null."); + + public static readonly MethodInfo UnwrapNullableMethod = typeof(ThrowHelpers).GetMethod(nameof(UnwrapNullable))!; + public static T UnwrapNullable(T? value, string expression, string type) where T : struct => + value ?? ThrowNullReference(expression, type); + } } } diff --git a/src/Tests/Binding/NullPropagationTests.cs b/src/Tests/Binding/NullPropagationTests.cs index 8a89309c4..666fd2318 100644 --- a/src/Tests/Binding/NullPropagationTests.cs +++ b/src/Tests/Binding/NullPropagationTests.cs @@ -155,7 +155,7 @@ private void TestExpression(Random rnd, Expression expression, ParameterExpressi Func compile(Expression e) => Expression.Lambda>(Expression.Convert(e, typeof(object)), parameter) // .CompileFast(); - .Compile(preferInterpretation: true); + .Compile(preferInterpretation: false); var withNullChecks = compile(exprWithChecks); var withoutNullChecks = compile(expr); @@ -224,7 +224,7 @@ private void TestExpression(Random rnd, Expression expression, ParameterExpressi private object EvalExpression(Expression> a, T val) { var nullChecked = ExpressionNullPropagationVisitor.PropagateNulls(a.Body, _ => true); - var d = a.Update(body: nullChecked, a.Parameters).Compile(preferInterpretation: true); + var d = a.Update(body: nullChecked, a.Parameters).Compile(preferInterpretation: false); return d(val); }