0

I have the following two POCOs:

private class Person
{
    public string Name { get; set; }
    public int? Age { get; set; }
}

private class PersonDto
{
    public string Name { get; set; }
    public int? Age { get; set; }
}

In my application, I want to implement the standard behavior that values which are null don't overwrite their targets when mapping them. This is the code I tried to execute:

var mapper = new MapperConfiguration(m =>
{
    m.CreateMap<Person, PersonDto>().ReverseMap();
    m.CreateMap(typeof(Nullable<>), typeof(Nullable<>)).ConvertUsing(typeof(NullableConverter<>));
}).CreateMapper();

var person = new Person
{
    Name = "Steve",
    Age = null
};
var personDto = new PersonDto
{
    Name = "Steve",
    Age = 20
};

var result = mapper.Map(person, personDto);
Console.WriteLine(personDto.Age);

I would expect the statment Console.WriteLine(personDto.Age); to print 20. The NullableConverter is implemented as follows:

public class NullableConverter<TSource> : ITypeConverter<TSource, TSource>
{
    public TSource Convert(TSource source, TSource destination, ResolutionContext context)
    {
        return source == null ? destination : source;
    }
}

Instead, I am greeted with the following exception in regards to the mapping of the Age property: System.InvalidCastException: Unable to cast object of type 'Test.NullableConverter´1[System.Int32]' to type 'AutoMapper.ITypeConverter´2[System.Nullable´1[System.Int32],System.Nullable´1[System.Int32]]'. This doesn't make sense to me. Why would AutoMapper be trying to assign a NullableConverter<int> to an ITypeConverter<int?, int?>. It's obvious that this won't work. Shouldn't it be trying to use a NullableConverter<int?>? This seems like buggy behavior. Am I missing something?

I am using AutoMapper v10

Collin Alpert
  • 475
  • 6
  • 14

1 Answers1

4

Specify Nullable (?) on your converter directly:

public class NullableConverter<TSource> : ITypeConverter<TSource?, TSource?> where TSource: struct
{
    public TSource? Convert(TSource? source, TSource? destination, ResolutionContext context)
    {
        return source.HasValue ? source : destination ;
    }
}

Also if you want to ignore all null source members you can do something like this.

Guru Stron
  • 102,774
  • 10
  • 95
  • 132
  • Good answer. Same I would did. Seems to be AutoMapper only uses concrete types like "int", "bool", "YourStruct", "YourClass" but not "Nullable" when creating converter of a generic type. Maybe because nullable types are not really concrete runtime types. More like compile features. – Marcus.D Jul 14 '20 at 10:19
  • 1
    Thanks, that works! You might want to switch the arguments in the ternary expression to `return source.HasValue ? source : destination` though ;) – Collin Alpert Jul 14 '20 at 11:18
  • @CollinAlpert fixed! :) and was glad to help! – Guru Stron Jul 14 '20 at 11:19