{"record":{"id":"620dd4bbf0be2223","repo":"dotnet/efcore","slug":"memberaccess-on-multi-dimensional-array","errorCode":null,"errorMessage":"MemberAccess on multi-dimensional array","messagePattern":"MemberAccess on multi-dimensional array","errorType":"exception","errorClass":"NotImplementedException","httpStatus":null,"severity":"error","filePath":"src/EFCore.Design/Query/Internal/CSharpToLinqTranslator.cs","lineNumber":804,"sourceCode":"        switch (memberInfo)\n        {\n            case Type nestedType:\n                return Constant(nestedType);\n\n            case null:\n                throw new InvalidOperationException($\"MemberAccess: couldn't find member '{memberSymbol.Name}': {memberAccess}\");\n        }\n\n        // Enum field constant\n        if (containingType.IsEnum)\n        {\n            return Constant(Enum.Parse(containingType, memberInfo.Name), containingType);\n        }\n\n        // array.Length\n        return expression.Type.IsArray && memberInfo.Name == \"Length\"\n            ? expression.Type.GetArrayRank() != 1\n                ? throw new NotImplementedException(\"MemberAccess on multi-dimensional array\")\n                : (Expression)ArrayLength(expression)\n            : MakeMemberAccess(\n                expression is ConstantExpression { Value: Type } ? null : expression,\n                memberInfo);\n    }\n\n    /// <summary>\n    ///     This is an internal API that supports the Entity Framework Core infrastructure and not subject to\n    ///     the same compatibility standards as public APIs. It may be changed or removed without notice in\n    ///     any release. You should only use it directly in your code with extreme caution and knowing that\n    ///     doing so can result in application failures when updating to a new Entity Framework Core release.\n    /// </summary>\n    public override Expression VisitObjectCreationExpression(ObjectCreationExpressionSyntax objectCreation)\n    {\n        if (_semanticModel.GetSymbolInfo(objectCreation).Symbol is not IMethodSymbol constructorSymbol)\n        {\n            throw new InvalidOperationException($\"ObjectCreation: couldn't find IMethodSymbol for constructor: {objectCreation}\");\n        }","sourceCodeStart":786,"sourceCodeEnd":822,"githubUrl":"https://github.com/dotnet/efcore/blob/3a2006ef569de08368d59db5e1468aa8f407e4f8/src/EFCore.Design/Query/Internal/CSharpToLinqTranslator.cs#L786-L822","documentation":"Thrown as NotImplementedException when a member access on `.Length` targets a multi-dimensional array (rank != 1). The translator special-cases `array.Length` for single-dimensional arrays by emitting an ArrayLength expression, but for multi-dimensional arrays it does not know how to represent the Length property (which on a multi-dim array returns the total element count, not something expression trees natively support) and throws.","triggerScenarios":"A precompiled query accesses `.Length` on a multi-dimensional array variable: `int[,] grid = ...; var query = ctx.Data.Where(d => grid.Length > 0 && d.Value > 0);`. The translator detects the array type has rank != 1 and throws NotImplementedException.","commonSituations":"Capturing multi-dimensional arrays (matrices, grids, 2D lookup tables) as variables in a precompiled query and referencing their Length property inside the query lambda. Common in scientific computing, gaming, GIS, or image-processing domains embedded in EF query code.","solutions":["Avoid referencing .Length on multi-dimensional arrays inside precompiled queries — capture the length as a separate int variable before the query and reference that: `int len = grid.Length; var query = ... len ...;`","Convert the multi-dimensional array to a single-dimensional array or a jagged array before the query.","If the array is a constant, hoist all logic involving it outside the query body so the translator never visits the member access.","File an issue to support multi-dimensional array Length in the translator if this is important for your scenario."],"exampleFix":"// before\nint[,] grid = LoadGrid();\nvar query = ctx.Cells.Where(c => grid.Length > 0 && c.Row < grid.GetLength(0));\n\n// after — extract what you need before the query\nint[,] grid = LoadGrid();\nint gridLength = grid.Length;\nint gridRows = grid.GetLength(0);\nvar query = ctx.Cells.Where(c => gridLength > 0 && c.Row < gridRows);","handlingStrategy":"validation","validationCode":"// Before precompiling, check for .Length access on multi-dimensional arrays\nvar multiDimLengthAccess = querySyntaxTree.DescendantNodes()\n    .OfType<MemberAccessExpressionSyntax>()\n    .Where(m =>\n    {\n        var exprType = semanticModel.GetTypeInfo(m.Expression).Type as IArrayTypeSymbol;\n        return m.Name.Identifier.Text == \"Length\" && exprType is { Rank: > 1 };\n    });\nif (multiDimLengthAccess.Any())\n    ReportError(\".Length on multi-dimensional arrays is not supported in precompiled queries\");","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Do not reference .Length or .GetLength() on multi-dimensional arrays inside precompiled query lambdas.","Extract array dimensions (lengths) into separate int variables before the query.","Convert multi-dimensional arrays to jagged arrays or flat arrays for use in precompiled queries.","Keep array operations outside the query body."],"tags":["precompiled-queries","roslyn","array","member-access","not-implemented","expression-tree"],"backgroundTag":null,"analyzedSha":"3a2006ef569de08368d59db5e1468aa8f407e4f8","analyzedAt":"2026-08-11T23:42:04.146Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}