I am experiencing exceptions when using value objects with implicit conversions within LINQ Where lambdas that are executed by the Marten document store.
I discovered this issue in this repository that fixes an exception around implicit/explicit conversion operators that was released in version 5.0.3. That particular version introduces a new exception in the code when implicit conversion operators are used (apparently) within a closure.
The example may be able to be distilled down a bit more, but this closely matches our production code while being. This test reproduces the issue on 5.0.3 and latest, but not 5.0.2 or latest 4.x.
public abstract class PrimitiveValueObject<TInput, TOutput>
{
public TInput Value { get; protected set; } = default!;
public static implicit operator
TInput(PrimitiveValueObject<TInput, TOutput>? primitiveValueObject) => primitiveValueObject == null
? default!
: primitiveValueObject.Value;
}
public class MyPrimitive : PrimitiveValueObject<string, MyPrimitive>
{
public MyPrimitive(string val) => Value = val;
}
[Fact]
public void Test()
{
var captured = new MyPrimitive("Hello world");
// Expression with implicit conversion on closure-captured variable
Expression<Func<string>> expr = () => captured;
// Wrap in Convert to object (common pattern in LINQ providers)
var toObject = Expression.Convert(expr.Body, typeof(object));
var lambda = Expression.Lambda<Func<object>>(toObject);
_testOutputHelper.WriteLine($"Expression: {lambda}");
// Standard Compile works
var standard = lambda.Compile();
_testOutputHelper.WriteLine($"Compile(): '{standard()}'");
// CompileFast throws
var fast = lambda.CompileFast();
_testOutputHelper.WriteLine($"CompileFast(): '{fast()}'");
}
System.IndexOutOfRangeException
Index was outside the bounds of the array.
at FastExpressionCompiler.ExpressionCompiler.EmittingVisitor.TryEmitConvert(UnaryExpression expr, IReadOnlyList1 paramExprs, ILGenerator il, ClosureInfo& closure, CompilerFlags setup, ParentFlags parent) at FastExpressionCompiler.ExpressionCompiler.EmittingVisitor.TryEmit(Expression expr, IReadOnlyList1 paramExprs, ILGenerator il, ClosureInfo& closure, CompilerFlags setup, ParentFlags parent, Int32 byRefIndex)
at FastExpressionCompiler.ExpressionCompiler.EmittingVisitor.TryEmitConvert(UnaryExpression expr, IReadOnlyList1 paramExprs, ILGenerator il, ClosureInfo& closure, CompilerFlags setup, ParentFlags parent) at FastExpressionCompiler.ExpressionCompiler.EmittingVisitor.TryEmit(Expression expr, IReadOnlyList1 paramExprs, ILGenerator il, ClosureInfo& closure, CompilerFlags setup, ParentFlags parent, Int32 byRefIndex)
at FastExpressionCompiler.ExpressionCompiler.TryCompileBoundToFirstClosureParam(Type delegateType, Expression bodyExpr, IReadOnlyList1 paramExprs, Type returnType, CompilerFlags flags) at FastExpressionCompiler.ExpressionCompiler.CompileFast[R](Expression1 lambdaExpr, Boolean ifFastFailedReturnNull, CompilerFlags flags)
at TestProject1.UnitTest1.Test() in /Users/kevin/source/server/src/TestProject1/UnitTest1.cs:line 41
at System.RuntimeMethodHandle.InvokeMethod(Object target, Void** arguments, Signature sig, Boolean isConstructor)
at System.Reflection.MethodBaseInvoker.InvokeWithNoArgs(Object obj, BindingFlags invokeAttr)
I will note that if I don't have the abstract class be abstract, I get InvalidProgramException instead. Not sure what makes that invalid.
I'm not familiar with this project or a lot of the nuance of expressions, but if I can be of help, let me know. Thank you for your help!
I am experiencing exceptions when using value objects with implicit conversions within LINQ
Wherelambdas that are executed by the Marten document store.I discovered this issue in this repository that fixes an exception around implicit/explicit conversion operators that was released in version
5.0.3. That particular version introduces a new exception in the code when implicit conversion operators are used (apparently) within a closure.The example may be able to be distilled down a bit more, but this closely matches our production code while being. This test reproduces the issue on
5.0.3and latest, but not5.0.2or latest4.x.I will note that if I don't have the
abstractclass beabstract, I getInvalidProgramExceptioninstead. Not sure what makes that invalid.I'm not familiar with this project or a lot of the nuance of expressions, but if I can be of help, let me know. Thank you for your help!