Skip to content

[BUG] Regression: Find(x => ids.Contains(x.id)) can throw on .NET 10, breaking LINQ-to-Bson translation #2670

@LPEdwin

Description

@LPEdwin

Version

  • LiteDB v5.0.21
  • .NET 10

Summary
On .NET 10 the common pattern

var ids = new[] { 1 };
var result = col.Find(x => ids.Contains(x.Id));

can fail because the compiler sometimes chooses the span-based overload. The captured array is implicitly converted to ReadOnlySpan and the expression tree contains an op_Implicit(...) node. LiteDB's LINQ-to-Bson translator does not currently handle that shape and throws when trying to translate the lambda.

Why this happens

The C# overload resolution rules changed: arrays can implicitly convert to ReadOnlySpan and the compiler may pick MemoryExtensions.Contains(ReadOnlySpan, T) over Enumerable.Contains(IEnumerable, T).
See: https://learn.microsoft.com/dotnet/core/compatibility/core-libraries/10.0/csharp-overload-resolution

Workaround
Convert to an IEnumerable explicitly:

var ids = new[] { 1 }.AsEnumerable();
var result = col.Find(x => ids.Contains(x.Id));

Expected behavior

The same code should translate to the same BsonExpression on .NET 9 and .NET 10 (e.g. @0 ANY = @1).

Proposed fix

Add a MemoryExtensionsResolver mapping MemoryExtensions.Contains -> @0 ANY = @1 (optionally also IndexOf, StartsWith, EndsWith).

In the LINQ expression visitor, narrowly unwrap op_Implicit conversions only when the conversion is using types of the following group ReadOnlySpan / Span / ReadOnlyMemory / Memory.
Use reflection checks with hardcoded type name comparisons so no project multitargeting is required.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions