LuckyPennySoftware/AutoMapper · error · InvalidOperationException

Type '{conditionType.Name}' does not implement IPreCondition

Error message

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

What it means

Thrown by PreCondition<TCondition>() when the generic type argument does not implement the IPreCondition<TSource, TDestination> interface. The CreatePreConditionExpression method calls GetGenericInterface(typeof(IPreCondition<,>)) and throws InvalidOperationException if null. This is analogous to the Condition<ICondition<,,>> check but for the simpler two-type-argument pre-condition interface.

Source

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

        ConditionCore((src, dest, srcMember, destMember, ctxt) => condition(src, dest, srcMember));
    public void Condition(Func<TSource, TDestination, bool> condition) => ConditionCore((src, dest, srcMember, destMember, ctxt) => condition(src, dest));
    public void Condition(Func<TSource, bool> condition) => ConditionCore((src, dest, srcMember, destMember, ctxt) => condition(src));
    protected void ConditionCore(Expression<Func<TSource, TDestination, TMember, TMember, ResolutionContext, bool>> expr) =>
        PropertyMapActions.Add(pm => pm.Condition = expr);
    public void PreCondition<TCondition>() where TCondition : IPreCondition<TSource, TDestination>
    {
        var expr = CreatePreConditionExpression(typeof(TCondition));
        PreConditionCore(expr);
    }
    protected Expression<Func<TSource, TDestination, ResolutionContext, bool>> CreatePreConditionExpression(Type conditionType)
    {
        var srcParam = Parameter(typeof(TSource));
        var destParam = Parameter(typeof(TDestination));
        var ctxParam = Parameter(typeof(ResolutionContext));

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

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

        // 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 callExpression = Call(
            Convert(conditionInstance, interfaceType),
            evaluateMethod,
            srcArg, destArg, ctxParam
        );

        return Lambda<Func<TSource, TDestination, ResolutionContext, bool>>(

View on GitHub (pinned to dfa6dd587c)

Solutions

  1. Implement IPreCondition<TSource, TDestination> on your pre-condition class with the exact same generic type arguments as the mapping.
  2. Alternatively, use one of the lambda PreCondition(...) overloads (e.g., PreCondition(src => src.IsValid)).
  3. Verify the generic arguments match the map's TSource and TDestination.

Example fix

// before — wrong interface
public class MyPreCondition : ICondition<Source, Dest, bool> { /* ... */ }
CreateMap<Source, Dest>().ForMember(d => d.X, opt => opt.PreCondition<MyPreCondition>());

// after — correct interface
public class MyPreCondition : IPreCondition<Source, Dest>
{
    public bool Evaluate(Source src, Dest dest, ResolutionContext ctx) => src.IsValid;
}
CreateMap<Source, Dest>().ForMember(d => d.X, opt => opt.PreCondition<MyPreCondition>());
Defensive patterns

Strategy: type-guard

Type guard

// Type guard: verify a type implements IPreCondition<TSource, TDestination>
static bool ImplementsPreCondition<TSource, TDestination>(Type preConditionType)
    => preConditionType.GetGenericInterface(typeof(IPreCondition<,>)) != null;

// Usage before configuring
if (!ImplementsPreCondition<Source, Dest>(typeof(MyPreCondition)))
    throw new InvalidOperationException($"{nameof(MyPreCondition)} must implement IPreCondition<Source, Dest>.");

Prevention

When it happens

Trigger: Calling .PreCondition<MyPreCondition>() inside a ForMember callback where MyPreCondition does not implement IPreCondition<TSource, TDestination>, or implements it with mismatched generic type arguments.

Common situations: Implementing the wrong interface; confusing IPreCondition with ICondition; type argument mismatch between the pre-condition's generic arguments and the mapping's source/destination types.

Related errors


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