{"record":{"id":"3124ee1a220f5041","repo":"devlooped/moq","slug":"ref-expression-must-evaluate-to-a-constant-value","errorCode":null,"errorMessage":"Ref expression must evaluate to a constant value.","messagePattern":"Ref expression must evaluate to a constant value\\.","errorType":"exception","errorClass":"NotSupportedException","httpStatus":null,"severity":"error","filePath":"src/Moq/MatcherFactory.cs","lineNumber":72,"sourceCode":"                        {\n                            var memberDeclaringType = member.DeclaringType!;\n                            if (memberDeclaringType.IsGenericType)\n                            {\n                                var memberDeclaringTypeDefinition = memberDeclaringType.GetGenericTypeDefinition();\n                                if (memberDeclaringTypeDefinition == typeof(It.Ref<>))\n                                {\n                                    return new Pair<IMatcher, Expression>(AnyMatcher.Instance, argument);\n                                }\n                            }\n                        }\n                    }\n\n                    if (argument.PartialEval() is ConstantExpression constant)\n                    {\n                        return new Pair<IMatcher, Expression>(new RefMatcher(constant.Value), constant);\n                    }\n\n                    throw new NotSupportedException(Resources.RefExpressionMustBeConstantValue);\n                }\n            }\n            else if (parameter.IsDefined(typeof(ParamArrayAttribute), true) && argument.NodeType == ExpressionType.NewArrayInit)\n            {\n                var newArrayExpression = (NewArrayExpression)argument;\n\n                Debug.Assert(newArrayExpression.Type.IsArray);\n                var elementType = newArrayExpression.Type.GetElementType()!;\n\n                var n = newArrayExpression.Expressions.Count;\n                var matchers = new IMatcher[n];\n                var initializers = new Expression[n];\n\n                for (int i = 0; i < n; ++i)\n                {\n                    (matchers[i], initializers[i]) = MatcherFactory.CreateMatcher(newArrayExpression.Expressions[i]);\n                    initializers[i] = initializers[i].ConvertIfNeeded(elementType);\n                }","sourceCodeStart":54,"sourceCodeEnd":90,"githubUrl":"https://github.com/devlooped/moq/blob/89a5be629c752960fe403e95ff583e4ae6f00542/src/Moq/MatcherFactory.cs#L54-L90","documentation":"Moq's MatcherFactory throws this NotSupportedException when a `Ref<T>` matcher argument's expression cannot be partially evaluated down to a constant value. `Ref` matches arguments by reference equality, so Moq must capture a constant value at setup time; if the expression is not constant (e.g. a variable or computed value), it cannot be used as a reference sentinel.","triggerScenarios":"Calling It.Is or a setup with `Ref` semantics (via MatcherFactory.CreateMatcher) where the argument expression passed to the ref parameter is not a constant, e.g. `mock.Setup(m => m.Method(ref someLocalVar))` with a non-const local.","commonSituations":"Developers passing a mutable local variable or computed value to a ref parameter in a setup, expecting Moq to capture it; Moq 4.x requires a constant expression for ref matchers.","solutions":["Use `new Ref<object>(value)` or pass a constant/readonly field value in the setup expression","Assign the value to a `const` or capture it via a typed Ref sentinel so PartialEval yields a ConstantExpression","If the value varies, use `It.Ref<object>.IsAny` instead of a fixed reference match"],"exampleFix":"// before\nobject value = GetValue();\nmock.Setup(m => m.DoWork(ref value)).Returns(true);\n// after\nmock.Setup(m => m.DoWork(ref It.Ref<object>.IsAny)).Returns(true);","handlingStrategy":"validation","validationCode":"var captured = value; // ensure the ref arg is a constant/local capture\nif (!(Expression.Constant(captured) is ConstantExpression)) throw new InvalidOperationException(\"Ref argument must be constant\");","typeGuard":"static bool IsConstantRef(object? v) => v is string or int or long or double or bool or null;","tryCatchPattern":"try { mock.Setup(m => m.DoWork(ref arg))... } catch (NotSupportedException ex) when (ex.Message.Contains(\"Ref expression\")) { /* use It.Ref<T>.IsAny */ }","preventionTips":["Use It.Ref<T>.IsAny for variable ref arguments","Only pass constants or Ref<T> wrappers for ref matching","Never pass mutable locals directly in ref setups"],"tags":["moq","ref-parameter","expression-evaluation","unsupported-expression"],"backgroundTag":"unsupported-operation","analyzedSha":"89a5be629c752960fe403e95ff583e4ae6f00542","analyzedAt":"2026-09-16T05:31:39.496Z","contentChangedAt":"2026-09-16T05:31:39.496Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}