LuckyPennySoftware/AutoMapper · error · InvalidOperationException

Type '{conditionType.Name}' does not implement ICondition<TS

Error message

Type '{conditionType.Name}' does not implement ICondition<TSource, TDestination, TMember>

What it means

Thrown by Condition<TCondition>() when the generic type argument does not implement the ICondition<TSource, TDestination, TMember> interface. The CreateConditionExpression method calls GetGenericInterface(typeof(ICondition<,,>)) and throws InvalidOperationException if the result is null, meaning no closed generic ICondition interface was found on the type.

Source

Thrown at src/AutoMapper/Configuration/MemberConfigurationExpression.cs:85

        _sourceMembers = ReflectionHelper.GetMemberPath(_sourceType, sourceMembersPath);
        PropertyMapActions.Add(pm => pm.MapFrom(sourceMembersPath, _sourceMembers));
    }
    public void Condition<TCondition>() where TCondition : ICondition<TSource, TDestination, TMember>
    {
        var expr = CreateConditionExpression(typeof(TCondition));
        ConditionCore(expr);
    }
    protected virtual Expression<Func<TSource, TDestination, TMember, TMember, ResolutionContext, bool>> CreateConditionExpression(Type conditionType)
    {
        var srcParam = Parameter(typeof(TSource));
        var destParam = Parameter(typeof(TDestination));
        var srcMemberParam = Parameter(typeof(TMember));
        var destMemberParam = Parameter(typeof(TMember));
        var ctxParam = Parameter(typeof(ResolutionContext));

        var conditionInstance = ServiceLocator(conditionType);
        var interfaceType = conditionType.GetGenericInterface(typeof(ICondition<,,>)) ??
            throw new InvalidOperationException($"Type '{conditionType.Name}' does not implement ICondition<TSource, TDestination, TMember>");
        var evaluateMethod = interfaceType.GetMethod("Evaluate");

        // Get the actual types from the interface
        var interfaceArgs = interfaceType.GenericTypeArguments;
        var expectedSourceType = interfaceArgs[0];
        var expectedDestType = interfaceArgs[1];
        var expectedMemberType = interfaceArgs[2];

        // Cast parameters to the expected types if needed
        var srcArg = typeof(TSource) == expectedSourceType ? srcParam : (Expression)Convert(srcParam, expectedSourceType);
        var destArg = typeof(TDestination) == expectedDestType ? destParam : (Expression)Convert(destParam, expectedDestType);
        var srcMemberArg = typeof(TMember) == expectedMemberType ? srcMemberParam : (Expression)Convert(srcMemberParam, expectedMemberType);
        var destMemberArg = typeof(TMember) == expectedMemberType ? destMemberParam : (Expression)Convert(destMemberParam, expectedMemberType);

        var callExpression = Call(
            Convert(conditionInstance, interfaceType),
            evaluateMethod,
            srcArg, destArg, srcMemberArg, destMemberArg, ctxParam

View on GitHub (pinned to dfa6dd587c)

Solutions

  1. Implement ICondition<TSource, TDestination, TMember> on your condition class with the exact same generic type arguments as the mapping.
  2. Alternatively, use one of the lambda Condition(...) overloads instead of a class-based condition.
  3. Double-check that the condition class's generic arguments match the source, destination, and member types of the ForMember call.

Example fix

// before — wrong interface
public class MyCondition : IValueResolver<Source, Dest, bool> { /* ... */ }
CreateMap<Source, Dest>().ForMember(d => d.IsActive, opt => opt.Condition<MyCondition>());

// after — correct interface with matching generic arguments
public class MyCondition : ICondition<Source, Dest, bool>
{
    public bool Evaluate(Source src, Dest dest, bool srcMember, bool destMember, ResolutionContext ctx) => srcMember;
}
CreateMap<Source, Dest>().ForMember(d => d.IsActive, opt => opt.Condition<MyCondition>());
Defensive patterns

Strategy: type-guard

Type guard

// Type guard: verify a type implements ICondition<TSource, TDestination, TMember>
static bool ImplementsCondition<TSource, TDestination, TMember>(Type conditionType)
    => conditionType.GetGenericInterface(typeof(ICondition<,,>)) != null;

// Usage before configuring
if (!ImplementsCondition<Source, Dest, bool>(typeof(MyCondition)))
    throw new InvalidOperationException($"{nameof(MyCondition)} must implement ICondition<Source, Dest, bool>.");

Prevention

When it happens

Trigger: Calling .Condition<MyCondition>() inside a ForMember callback where MyCondition implements IValueResolver or some other interface instead of ICondition<TSource, TDestination, TMember>. Also happens when MyCondition implements ICondition with different generic type arguments than the map's TSource/TDestination/TMember.

Common situations: Implementing the wrong interface by mistake; using a value resolver class where a condition class was expected; type argument mismatch between the condition's generic arguments and the mapping's types.

Related errors


AI-assisted analysis of LuckyPennySoftware/AutoMapper@dfa6dd587c (2026-08-13). Data as JSON: /api/errors/6ebd9e2a18954c35. Report an issue: GitHub.