Skip to content

Unable to map nullable primitive types (string? to bool?) using custom MapWith delegate #992

Description

@vzalamea

What am I missing?

Image
using Mapster;
using MapsterMapper;

TypeAdapterConfig config = new TypeAdapterConfig();
config.NewConfig<string?, bool?>().MapWith(src => Helper.ParseToNullableBool(src));
config.Compile();

Mapper mapper = new Mapper(config);

Source source = new Source { Prop1 = "yes" };
Destination destination = mapper.Map<Destination>(source);

Console.ReadLine();

static class Helper
{
    public static bool? ParseToNullableBool(string? value)
    {
        if (string.IsNullOrWhiteSpace(value))
            return null;

        return value.Trim().ToLower() switch
        {
            "true" or "t" or "yes" or "1" => true,
            "false" or "f" or "no" or "0" => false,
            _ => null
        };
    }
}

class Source
{
    public string? Prop1 { get; set; }
}

class Destination
{
    public bool? Prop1 { get; set; }
}

converting non-nullable string to non-nullable bool works fine

Image

Activity

  1. DocSvartz commented on Jun 25, 2026

    @DocSvartz
    Contributor

    @vzalamea What Version of Mapster you using?

  2. vzalamea commented on Jun 25, 2026

    @vzalamea
    Author

    works in 10.0.8. broken in 10.0.9

  3. DocSvartz commented on Jun 25, 2026

    @DocSvartz
    Contributor

    in 10.0.9 Nullable can using not nullable Mapping settings. Try using this:

    config.NewConfig<string, bool>().MapWith(src => Helper.ParseToNullableBool(src));
    
    class Source
    {
        public string? Prop1 { get; set; }
    }
    
    class Destination
    {
        public bool? Prop1 { get; set; }
    }
    
  4. nghiaphamhn commented on Jul 13, 2026

    @nghiaphamhn

    I'm seeing the same issue.

    I have a global converter:

    TypeAdapterConfig.GlobalSettings
        .ForType<DateTime?, long?>()
        .MapWith(src => src.ToSecondsTimestamp());

    Source:

    public DateTime? CreatedAt { get; set; }

    Destination:

    public long? CreatedAt { get; set; }

    Calling:

    var dto = entity.Adapt<TimeLogExtendRsRes>();

    throws:

    System.InvalidOperationException: Nullable object must have a value.
    
  5. DocSvartz commented on Jul 14, 2026

    @DocSvartz
    Contributor

    Hi, @nghiaphamhn This is due to the addition of support for using mapping settings for ValueType when mapping its Nullable representations: .Adapt<DateTime?, long?>(), .Adapt<DateTime, long?>() , .Adapt<DateTime?, long>()
    will automatically use the settings for ForType<DateTime, long> unless you specify a more specific equivalent: .ForType<DateTime?, long?>() or .ForType<DateTime, long?>() or .ForType<DateTime?, long>().

    This was the original idea, but it seems there were problems with the prioritization of settings.

    Your case should work correctly in version 10.0.10 If you don't have a custom converter installed for .ForType<DateTime, long>(), it will still have higher priority. It will be fixed in the next version.

  6. nghiaphamhn commented on Jul 14, 2026

    @nghiaphamhn

    Thanks for the explanation, @DocSvartz

    In my case, I explicitly configured converters for all nullable and non-nullable combinations:

    GlobalConfig.ForType<DateTime, long>().MapWith(src => (long)src.ToSecondsTimestamp());
    GlobalConfig.ForType<DateTime?, long>().MapWith(src => (long)src.ToSecondsTimestamp());
    GlobalConfig.ForType<DateTime, long?>().MapWith(src => src.ToSecondsTimestamp());
    GlobalConfig.ForType<DateTime?, long?>().MapWith(src => src.ToSecondsTimestamp());
    GlobalConfig.ForType<long, DateTime>().MapWith(src => src.FromUnixTimeStamp());
    GlobalConfig.ForType<long, DateTime?>().MapWith(src => src.FromUnixTimeStamp());
    GlobalConfig.ForType<long?, DateTime>().MapWith(src => (DateTime)src.FromUnixTimeStamp());
    GlobalConfig.ForType<long?, DateTime?>().MapWith(src => src.FromUnixTimeStamp());

  7. nghiaphamhn commented on Jul 14, 2026

    @nghiaphamhn

    Just to clarify, I'm currently using Mapster 10.0.10, and the issue still occurs with my configuration.
    The same configuration works correctly on 10.0.8. The issue only appears after upgrading to 10.0.9 and 10.0.10.

  8. DocSvartz commented on Jul 14, 2026

    @DocSvartz
    Contributor

    @nghiaphamhn I think I understood what the problem is.

    GlobalConfig.ForType<DateTime?, long>().MapWith(src => (long)src.ToSecondsTimestamp());

    it is valid only DateTime is not null
    Otherwise, you will get the error you are talking about: System.InvalidOperationException: Nullable object must have a value.

    It's safer to use this:

    src.ToSecondsTimestamp().GetValueOrDefault();

    I think this will also be fixed and will work as before.

  9. linked a pull request that will close this issuefix #992 and fix #996 #999on Jul 15, 2026
  10. added a commit that references this issue on Jul 15, 2026
    4d7ad45
  11. nghiaphamhn commented on Jul 20, 2026

    @nghiaphamhn

    Thanks @DocSvartz , this solution works correctly now:

    src.ToSecondsTimestamp().GetValueOrDefault();

    The Nullable object must have a value error is no longer occurring.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions