Search code examples
c#automapperautomapper-11

AutoMapper 11 behaviors of mapping ReadOnlyCollection property


I'm new to AutoMapper, I want to post this issue on their github, but considering their issue template:

If you're new to AutoMapper, please ask a question on StackOverflow first and come back here if the people there consider it a bug.

I have to post here.

To simplify the problem, I removed unnecessary code as much as possible.

class Rule {
    public ReadOnlyCollection<string>? Collection { get; set; }
}

var config = new MapperConfiguration(c => {
    c.CreateMap<Rule, Rule>();
});
config.AssertConfigurationIsValid();

var mapper = config.CreateMapper();

var source = new Rule {
    Collection = Array.AsReadOnly(new [] { "a", "b", "c" })
};
var destination = new Rule();

// The following line throw an exception: 
// ArgumentException: System.Collections.ObjectModel.ReadOnlyCollection`1[System.String] 
// needs to have a constructor with 0 args or only optional args.
// Validate your configuration for details.
mapper.Map(source, destination); 

And docs said:

When calling Map with an existing readonly collection, such as IEnumerable<>, the setter will be used to replace it. If you actually have to map into that collection, you need to change its type to a writable collection, such as List<>, HashSet<>, ICollection<>, IList<> or IList. Alternatively, you can remove the setter or set UseDestinationValue.

But the exception seems tell me mapper is going to do a deep clone rather than the setter will be used to replace it.

AutoMapper version: 11.0.1

enter image description here


Solution

  • I'm sorry for my recklessness.

    In fact, the Rule class has more than one ReadOnlyCollection<string>? property:

    class Rule {
        public ReadOnlyCollection<string>? CollectionA { get; set; }
        public ReadOnlyCollection<string>? CollectionB { get; set; }
    }
    

    So, the following code as my origin question never initialize the CollectionB:

    var source = new Rule {
        CollectionA = Array.AsReadOnly(new [] { "a", "b", "c" })
    };
    var destination = new Rule();
    
    mapper.Map(source, destination); 
    

    It cause the null issue of AutoMapper, the solution is append ForAllMembers(o => o.AllowNull()) when CreateMap

    var config = new MapperConfiguration(c => {
        c.CreateMap<Rule, Rule>().ForAllMembers(o => o.AllowNull());
    });
    

    SORRY, EVERYONE!!!