Skip to content

Fix IndexOutOfRangeException when an Enum's MetadataToken collides with Nullable<T> - #472

Open
VSteeph wants to merge 1 commit into
DataObjects-NET:masterfrom
VSteeph:fix-metadatatoken-collision
Open

Fix IndexOutOfRangeException when an Enum's MetadataToken collides with Nullable<T>#472
VSteeph wants to merge 1 commit into
DataObjects-NET:masterfrom
VSteeph:fix-metadatatoken-collision

Conversation

@VSteeph

@VSteeph VSteeph commented Aug 10, 2026

Copy link
Copy Markdown

---Context

This PR comes from an issue we encountered. We started getting an IndexOutOfRangeException on a simple query that filters an entity based on its enum values:
result.Where(r => statuses.Contains(r.ProcessingInformation.ProcessingStatus));

---Root Cause

TupleLayout.ValueFieldAccessorResolver.GetValue decides whether a type is Nullable by comparing the MetadataToken alone. The problem is that a MetadataToken is unique only within a single module, not globally. Our enum lives in an application assembly and happened to be assigned the same token as Nullable<> from CoreLib, so it was sent down the nullable branch. Once it reached TryResolveNullableEnum, which assumes the type is generic and calls GetGenericArguments()[0], the exception was thrown.

---Fix

Use of the module in addition to the MetadataToken in the condition, so the combination is unique.

---Performance

I understand the original comparison was an optimisation to save a few CPU operations. Je However, GetValue runs when the tuple layout is built and the descriptors should be cached, so this doesn't seem to be a hot path Nevertheless, here is a screenshot of a benchmark showing the differences:

image

Code used for the benchmark:

private enum SampleEnum { A, B }

private static readonly int NullableTypeMetadataToken = typeof(Nullable<>).MetadataToken;
private static readonly Module NullableTypeModule = typeof(Nullable<>).Module;

private static readonly Type[] Types = {
  typeof(int), typeof(int?), typeof(long), typeof(Guid),
  typeof(bool), typeof(DateTime?), typeof(SampleEnum), typeof(SampleEnum?),
  typeof(string), typeof(decimal?)
};

[Benchmark(Baseline = true)]
public int Xor()
{
  var hits = 0;
  foreach (var t in Types) {
    if ((t.MetadataToken ^ NullableTypeMetadataToken) == 0) {
      hits++;
    }
  }
  return hits;
}

[Benchmark]
public int TokenAndModule()
{
  var hits = 0;
  foreach (var t in Types) {
    if (t.MetadataToken == NullableTypeMetadataToken && ReferenceEquals(t.Module, NullableTypeModule)) {
      hits++;
    }
  }
  return hits;
}

@VSteeph VSteeph changed the title Fix IndexOutOfRangeException when an Enum's MetadataToken collides wi… Fix IndexOutOfRangeException when an Enum's MetadataToken collides with Nullable<T> Aug 11, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant