dotnet/BenchmarkDotNet · error · ArgumentException

Extend a MethodCallExpression, but got a

Error message

Extend a MethodCallExpression, but got a 

What it means

GetReportFor<T> requires the expression body to be a MethodCallExpression so it can read the invoked MethodInfo. It throws ArgumentException with the actual body type name when the lambda is not a direct method invocation (e.g. a property access, field access, arithmetic, or conversion).

Source

Thrown at src/BenchmarkDotNet/Extensions/ReportExtensions.cs:15

using BenchmarkDotNet.Mathematics;
using BenchmarkDotNet.Reports;
using System.Linq.Expressions;

namespace BenchmarkDotNet.Extensions
{
    public static class ReportExtensions
    {
        public static BenchmarkReport GetReportFor<T>(this Summary summary, Expression<Action<T>> actionExp)
        {
            if (actionExp.Body == null)
                throw new ArgumentException("Extend a an Expression with a valid Body", nameof(actionExp));

            if (!(actionExp.Body is MethodCallExpression methodExp))
                throw new ArgumentException("Extend a MethodCallExpression, but got a " + actionExp.Body.GetType().Name, nameof(actionExp));

            return summary.Reports.First(r => r.BenchmarkCase.Descriptor.WorkloadMethod == methodExp.Method);
        }

        public static IList<Measurement> GetRunsFor<T>(this Summary summary, Expression<Action<T>> actionExp)
        {
            return summary.GetReportFor(actionExp).GetResultRuns().ToList();
        }

        public static Statistics GetStatistics(this IReadOnlyCollection<Measurement> runs)
        {
            if (runs.IsEmpty())
                throw new InvalidOperationException("List of measurements contains no elements");
            return new Statistics(runs.Select(r => r.GetAverageTime().Nanoseconds));
        }

        public static Statistics GetStatistics(this IEnumerable<Measurement> runs) =>
            GetStatistics(runs.ToList());

View on GitHub (pinned to b515068b61)

Solutions

  1. Pass a lambda that directly invokes the benchmark method: summary.GetReportFor(b => b.MyBenchmark()).
  2. Ensure the lambda contains exactly one method call and no wrapping conversions, ternaries, or member accesses.
  3. If you only have a MethodInfo, locate the report manually via summary.Reports.First(r => r.BenchmarkCase.Descriptor.WorkloadMethod == method).

Example fix

// before
var report = summary.GetReportFor(b => b.SomeProperty);

// after
var report = summary.GetReportFor(b => b.Run());
Defensive patterns

Strategy: type-guard

Validate before calling

Expression<Action<T>> expr = b => b.Run();
if (expr.Body is not MethodCallExpression mce)
    throw new InvalidOperationException("expression body must be a method call");
var report = summary.GetReportFor(expr);

Type guard

static bool IsMethodCallExpression<T>(Expression<Action<T>> expr) => expr?.Body is MethodCallExpression;

Prevention

When it happens

Trigger: Calling summary.GetReportFor(b => b.SomeProperty), summary.GetReportFor(b => b.Field), summary.GetReportFor(b => 1 + 1), or any lambda whose body is not a method call.

Common situations: Misunderstanding the API as a generic expression evaluator; passing a property getter or a composed expression instead of a single method-call lambda; refactoring a benchmark from a method to a property and forgetting to update the call.

Related errors


AI-assisted analysis of dotnet/BenchmarkDotNet@b515068b61 (2026-08-13). Data as JSON: /api/errors/3aa6afadadbf7741. Report an issue: GitHub.