Search code examples
c#automapper

An expression tree may not contain an 'is' pattern-matching operator


I am trying to use Automapper to map these properties

public class SourceClass
{
    public object emailNotification { get; set; }
}

public class DestinationClass
{
    public int emailNotificationId { get; set; }
    public string emailNotificationLookupName { get; set; }
}

When I debug it, emailNotification = ValueKind = Object : "{ "id": 3, "lookupName": "Send Email Notification" }".

The expected outcome is

  • emailNotificationId = 3
  • emailNotificationLookupName = "Send Email Notification"

This is my current code for mapping, but I have this compilation errror: An expression tree may not contain an 'is' pattern-matching operator. in src.emailNotification is JObject jObject

public class SourceProfile : AutoMapper.Profile
{
    public SourceProfile()
    {
        CreateMap<SourceClass, DestinationClass>()     
            .ForMember(dest => dest.emailNotificationId, opt => opt.MapFrom(src =>
                src.emailNotification != null && src.emailNotification is JObject jObject ? jObject["id"].Value<int>() : 0))
            .ForMember(dest => dest.emailNotificationLookupName, opt => opt.MapFrom(src =>
                src.emailNotification != null && src.emailNotification is JObject jObject ? jObject["lookupName"].Value<string>() : null))
        ;
                        
    }
}

After trying out both solutions from Yong Shun, I could compile without error but I still could not get the value mapped.

enter image description here

enter image description here

New screenshot enter image description here


Solution

  • You can use the as operator for the type-casting to replace the is in order to resolve the issue:

    CreateMap<SourceClass, DestinationClass>()     
        .ForMember(dest => dest.emailNotificationId, opt => opt.MapFrom(src =>
            src.emailNotification != null ? JObject.FromObject(src.emailNotification)["id"].Value<int>() : 0))
        .ForMember(dest => dest.emailNotificationLookupName, opt => opt.MapFrom(src =>
            src.emailNotification != null ? JObject.FromObject(src.emailNotification)["lookupName"].Value<string>() : null))
    

    Since the logic to validate the emailNotification is not null and type-casting to JObject duplicate in multiple places, you may consider migrating the logic in the AfterMap action:

    CreateMap<SourceClass, DestinationClass>()     
        .AfterMap((src, dest, context) =>
        {
            if (src.emailNotification != null)
            {
                JObject jObject = JObject.FromObject(src.emailNotification);
                dest.emailNotificationId = jObject["id"].Value<int>();
                dest.emailNotificationLookupName = jObject["lookupName"].Value<string>();
            }
        });
    

    Updated

    Note that the emailNotification show the value ValueKind = Object which is the JsonElement from System.Text.Json. Thus you need to take additional step in order to converting to JObject.

    JObject jObject = JObject.Parse(src.emailNotification.ToString());