11.0.1 not mapping properties when destination class has constructor with optional parameters #4101
-
With AutoMapper v11.0.1, there are some cases where source types will fail to map to destination types if destination types contain a constructor with optional parameters. This behaviour has been narrowed down to a change produced as part of this commit, specifically the change to the Prior to this commit, this method would exclude constructor parameters that were optional (i.e. had default values) but now it includes them. This in turn changes the assignment function that gets created in Further details and a full investigation history can be seen on this StackOverflow post. Source/destination typesSource types: public class ParentWriteModel
{
public ICollection<ChildWriteModel> Children { get; init; }
}
public class ChildWriteModel
{
public int Foo { get; init; }
} Destination types: /// <summary>
/// Parents will indirectly own zero to many <c>Child</c> objects through a <c>ChildGroup</c>.
/// </summary>
public class Parent
{
public Parent(ChildGroup? childGroup = null)
{
ChildGroup = childGroup;
}
public ChildGroup ChildGroup { get; private init; }
}
/// <summary>
/// Encapsulates a collection of <c>Child</c> objects and potentially exposes methods to perform aggregate operations on them.
/// </summary>
public class ChildGroup
{
public ChildGroup(ICollection<Child> thresholds)
{
Children = thresholds.ToList();
}
public IReadOnlyCollection<Child> Children { get; } = null!;
}
/// <summary>
/// A simple class at the bottom of the class composition hierarchy.
/// </summary>
public class Child
{
public Child(int foo)
{
Foo = foo;
}
public int Foo { get; private init; }
} Mapping configurationpublic class ExampleProfile : Profile
{
public ExampleProfile()
{
CreateMap<ParentWriteModel, Parent>().ForMember(
dest => dest.ChildGroup,
opt => opt.MapFrom((src, _, _, ctx) =>
{
// For v11+, this lambda doesn't get called if 'Parent' contains a constructor with optional parameters.
return new ChildGroup(ctx.Mapper.Map<List<Child>>(src.Children));
}));
CreateMap<ChildWriteModel, Child>();
}
} Version: 11.0.1Expected behaviorAssume the following write model: var children = new List<ChildWriteModel>
{
new()
{
Foo = 1
},
new()
{
Foo = 2
},
new()
{
Foo = 3
}
};
return new ParentWriteModel
{
Children = children
}; And the following map: var parent = mapper.Map<Parent>(writeModel);
var count = parent.ChildGroup?.Children.Count; In v10, all properties would have mapped successfully to the destination types and Actual behaviorIn v11, the Steps to reproduce
|
Beta Was this translation helpful? Give feedback.
Replies: 1 comment
-
That's by design, you'll have to change your code accordingly. |
Beta Was this translation helpful? Give feedback.
That's by design, you'll have to change your code accordingly.