.NET 10 Linq Query problem with Contains

Posts   
 
    
mbp
User
Posts: 29
Joined: 03-Jun-2021
# Posted on: 12-Nov-2025 08:43:00   

Hello,

We are upgrading to .NET 10, but there is a specific type of query that always fails.

Code is:

var metadata = new LinqMetaData(adapter);
var expectedUsers = new string[] { "John Doe" };
var results = metadata.User.Where(x => expectedUsers.Contains(x.Name)).ToList();

The following exception is thrown:

The Contains method on the type System.MemoryExtensions isn't convertable to an LLBLGen Pro construct.
   at SD.LLBLGen.Pro.LinqSupportClasses.ExpressionHandlers.PreProcessor.HandleMethodCallContains(MethodCallExpression expressionToHandle)
   at SD.LLBLGen.Pro.LinqSupportClasses.ExpressionHandlers.PreProcessor.HandleMethodCallExpression(MethodCallExpression expressionToHandle)
   at SD.LLBLGen.Pro.LinqSupportClasses.ExpressionHandlers.GenericExpressionHandler.HandleExpression(Expression expressionToHandle)
   at SD.LLBLGen.Pro.LinqSupportClasses.ExpressionHandlers.PreProcessor.HandleExpression(Expression expressionToHandle)
   at SD.LLBLGen.Pro.LinqSupportClasses.ExpressionHandlers.GenericExpressionHandler.HandleLambdaExpression(LambdaExpression expressionToHandle)
   at SD.LLBLGen.Pro.LinqSupportClasses.ExpressionHandlers.GenericExpressionHandler.HandleExpression(Expression expressionToHandle)
   at SD.LLBLGen.Pro.LinqSupportClasses.ExpressionHandlers.PreProcessor.HandleExpression(Expression expressionToHandle)
   at SD.LLBLGen.Pro.LinqSupportClasses.ExpressionHandlers.PreProcessor.HandleMethodCallWhere(MethodCallExpression expressionToHandle)
   at SD.LLBLGen.Pro.LinqSupportClasses.ExpressionHandlers.PreProcessor.HandleQueryableExtensionMethod(MethodCallExpression expressionToHandle)
   at SD.LLBLGen.Pro.LinqSupportClasses.ExpressionHandlers.PreProcessor.HandleMethodCallPerType(MethodCallExpression expressionToHandle, Type declaringType)
   at SD.LLBLGen.Pro.LinqSupportClasses.ExpressionHandlers.PreProcessor.HandleMethodCallExpression(MethodCallExpression expressionToHandle)
   at SD.LLBLGen.Pro.LinqSupportClasses.ExpressionHandlers.GenericExpressionHandler.HandleExpression(Expression expressionToHandle)
   at SD.LLBLGen.Pro.LinqSupportClasses.ExpressionHandlers.PreProcessor.HandleExpression(Expression expressionToHandle)
   at SD.LLBLGen.Pro.LinqSupportClasses.LLBLGenProProviderBase.HandleExpressionTree(Expression expression)
   at SD.LLBLGen.Pro.LinqSupportClasses.LLBLGenProProviderBase.PerformExecute(Expression expression, Type resultType)
   at SD.LLBLGen.Pro.LinqSupportClasses.LLBLGenProProviderBase.System.Linq.IQueryProvider.Execute(Expression expression)
   at SD.LLBLGen.Pro.LinqSupportClasses.LLBLGenProQuery`1.Execute()
   at SD.LLBLGen.Pro.LinqSupportClasses.LLBLGenProQuery`1.System.Collections.Generic.IEnumerable<T>.GetEnumerator()
   at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection)
   at System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source)
Otis avatar
Otis
LLBLGen Pro Team
Posts: 39988
Joined: 17-Aug-2003
# Posted on: 12-Nov-2025 09:01:41   

I haven't read about any breaking changes in this area. Does the query work in .net 9 or earlier? It looks like the Contains method (which is an extension method) matches with another one than the Enumerable one. Maybe it work if you use a List<string> instead of a string array ...

Frans Bouma | Lead developer LLBLGen Pro
mbp
User
Posts: 29
Joined: 03-Jun-2021
# Posted on: 12-Nov-2025 09:11:16   

Otis wrote:

I haven't read about any breaking changes in this area. Does the query work in .net 9 or earlier? It looks like the Contains method (which is an extension method) matches with another one than the Enumerable one. Maybe it work if you use a List<string> instead of a string array ...

Yes, it worked in .NET 9. We are unable to upgrade to .NET 10 due to this issue.

It works with List<string> instead. However our code base is quite large, so it's not feasible to refactor everything.

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39988
Joined: 17-Aug-2003
# Posted on: 12-Nov-2025 10:51:56   

That's unfortunate, but what Microsoft introduces isn't always our problem to solve, please do realize that. Also, please do realize that although microsoft released .net 10 yesterday, the only IDE that works with it is Rider, so please don't expect us to support .NET 10 right away (I mean, their own IDE team couldn't be bothered). We did evaluate .NET 10 from the documentation and didn't see any breaking changes we should address, as this one is unexpected.

Looking into this, the string array is arriving at the Contains() handler as an in-memory evaluation expression, which tells our handler to evaluate it on the spot as it's an object to be pulled into the query. This is in both .net 9 and .net 10 the case.

In .net 9 and earlier, it's a Constant expression with as value the string[]constant, however in .net 10 it's a ConvertExpression which tries to convert the string[] to a ReadOnlySpan. As this is unexpected, the handler fails. Contains can be present on a lot of objects so we built-in code paths for the ones which we can understand.

This is rather easy to fix however, we can simply remove the Convert expression and obtain the constant expression which is the array and this works fine. However I fear in other places this might still cause issues. We'll see if we can run our tests on .net 10 and see if things break somewhere. We'll then release a hotfix build.

Frans Bouma | Lead developer LLBLGen Pro
mbp
User
Posts: 29
Joined: 03-Jun-2021
# Posted on: 12-Nov-2025 10:59:21   

They also released VS 2026 and this IDE works with .NET 10

I am looking much forward to a hotfix, and I can provide more feedback if anything else break, we have a quite full integration test suite which will tell us if any queries are not working as expected.

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39988
Joined: 17-Aug-2003
# Posted on: 12-Nov-2025 11:06:24   

2026 is an insiders build. Not really going to touch that (with the mess they made of 2022's still in my memory wink ) The new rider works tho

In any case, I see 1 thing breaking after this, which is these kind of constructs: where !(new string[] { "FISSA", "PARIS" }.Contains(c.CustomerId))

before, this was a new array expression but now it's an op_implicit method call expression which converts it to a readonlyspan.

The idea again is to remove that one, but this is more problematic. Luckily it's in 1 spot in the pipeline, so we don't have to add code all over the place

Frans Bouma | Lead developer LLBLGen Pro
Otis avatar
Otis
LLBLGen Pro Team
Posts: 39988
Joined: 17-Aug-2003
# Posted on: 12-Nov-2025 12:43:36   

All our 8000+ tests seem to pass, so we've released a hotfix build, 5.12.2 which contains a fix for this (nuget packages are pushed but might take a while to be visible).

We had to fix it in 2 places, but should cover different ways to init an array, and multi-dimensional arrays. Let us know if you have a test that fails, so we can reproduce it. As nuget package versioning sucks, we might be required to push a new update tomorrow instead of today if there are still issues.

Frans Bouma | Lead developer LLBLGen Pro
mbp
User
Posts: 29
Joined: 03-Jun-2021
# Posted on: 12-Nov-2025 14:04:21   

Initial testing of this hotfix is very good, all of our integration tests are passing. Thanks!

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39988
Joined: 17-Aug-2003
# Posted on: 12-Nov-2025 14:45:27   

mbp wrote:

Initial testing of this hotfix is very good, all of our integration tests are passing. Thanks!

That's great news! simple_smile

The breaking change that causes this is: https://learn.microsoft.com/en-us/dotnet/core/compatibility/core-libraries/10.0/csharp-overload-resolution

Frans Bouma | Lead developer LLBLGen Pro