0

I have a problem mapping a property containing a custom list that inherits from IEnumerable (if i remove that inheritance, this example works). I have simplified the problem into this model:

public interface IMyEnumerable<T> : IEnumerable<T> { }
public class MyIEnumerable<T> : IMyEnumerable<T>
{
    private readonly IEnumerable<T> _items;

    public MyIEnumerable(IEnumerable<T> items)
    {
        _items = items;
    }

    public IEnumerator<T> GetEnumerator()
    {
        return _items.GetEnumerator();
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }
}

public class Source
{
    public List<SourceItem> Items { get; set; }
}

public class Destination
{
    public IMyEnumerable<DestinationItem> Items { get; set; }
}

public class SourceItem
{
    public string Name { get; set; }
}

public class DestinationItem
{
    public string Name { get; set; }
}

Then i try to use is this way:

public class MyResolver : ValueResolver<Source, IMyEnumerable<DestinationItem>>
{
    protected override IMyEnumerable<DestinationItem> ResolveCore(Source source)
    {
        var destinationItems = Mapper.Map<List<SourceItem>, IEnumerable<DestinationItem>>(source.Items);
        return new MyIEnumerable<DestinationItem>(destinationItems);
    }
}

// Mappings
Mapper.CreateMap<Source, Destination>()
    .ForMember(x => x.Items, m => m.ResolveUsing<MyResolver>());
Mapper.CreateMap<SourceItem, DestinationItem>();

// Using the mappings
var source = // not really relevant
var destination = Mapper.Map<Destination>(source);

This gives me the following exception (slightly edited for readability):

Mapping types:
MyIEnumerable`1 -> IMyEnumerable`1
MyIEnumerable`1[[DestinationItem]] -> IMyEnumerable`1[[DestinationItem]]

Destination path:
Destination.Items.Items

Source value:
MyIEnumerable`1[DestinationItem]
  ----> System.ArgumentException : Object of type System.Collections.Generic.List`1[DestinationItem] cannot be converted to type IMyEnumerable`1[DestinationItem].

Any idea how i can fix the mapping so that i can get this to work?

carl
  • 375
  • 4
  • 17
  • Is there an innerException? In my experience, there's usually an error in the nested types rather than the collection itself. – Eris Nov 28 '14 at 19:25
  • Yes, the inner exception says``Object of type System.Collections.Generic.List`1[DestinationItem] cannot be converted to type IMyEnumerable`1[DestinationItem].`` But if I remove the inheritance of IEnumerable from IMyEnumerable, it all works, so it does seem like it's got to do with automapper handling my class differently becuase it _is_ an IEnumerable... – carl Dec 01 '14 at 12:01
  • You say `source` is not really relevant, but it is. We have no idea what type `source` is, since you just called it a `var`. – Eris Dec 01 '14 at 19:27
  • source is initiated like this var source = new Source { Items = new List(new[] { new SourceItem { Name = "Test 1" }, new SourceItem { Name = "Test 2" } }) }; – carl Dec 02 '14 at 08:27

1 Answers1

0

Assuming the following:

var source = new Source
{
    Items = new List<SourceItem>
    {
        new SourceItem { Name = "foo" },
        new SourceItem { Name = "bar" },
        new SourceItem { Name = "cow" },
    }
};

Then the following work:

// Method 1: Straight up mapping the collections: 
Mapper.CreateMap<List<SourceItem>, IMyEnumerable<DestinationItem>>()
    .ConstructUsing(list => new MyEnumerable<DestinationItem>(list.ConvertAll(Mapper.Map<SourceItem, DestinationItem>)));

// Method 2: Ignore the property and do it ourselves after the rest of the mapping:
Mapper.CreateMap<Source, Destination>()
    .ForMember(q => q.Items, r => r.Ignore())
    .AfterMap((s, d) => d.Items = new MyEnumerable<DestinationItem>(
            s.Items.Select(Mapper.Map<SourceItem, DestinationItem>)));

Nothing else seems to work due to some combination of covariance and contravariance between List<T>, IEnumerable<T> and IMyEnumerable<T>

Eris
  • 7,378
  • 1
  • 30
  • 45
  • Method no 1 would not work for me because in my actual implementation i need information from the source model to create my destination list, not just from the source list. Method no 2 is more or less what i'm doing right now, but that just seems like a manual workaround for a bug... – carl Dec 02 '14 at 08:48
  • It probably is, you should go add an Issue on github – Eris Dec 03 '14 at 18:56
  • [Issue is up](https://github.com/AutoMapper/AutoMapper/issues/635) since a few days ago, no response yet though :-( – carl Dec 04 '14 at 08:57