AutoMapper映射到可空属性的属性

Dav*_*ner 10 c# automapper

如何将属性映射到可能为null的子属性?

例如,以下代码将因NullReferenceException而失败,因为Contact的User属性为null.

using AutoMapper;

namespace AutoMapperTests
{
    class Program
    {
        static void Main( string[] args )
        {
            Mapper.CreateMap<Contact, ContactModel>()
                .ForMember( x => x.UserName,  opt => opt.MapFrom( y => y.User.UserName ) );

            Mapper.AssertConfigurationIsValid();

            var c = new Contact();

            var co = new ContactModel();

            Mapper.Map( c, co );
        }
    }

    public class User
    {
        public string UserName { get; set; }
    }

    public class Contact
    {
        public User User { get; set; }
    }

    public class ContactModel
    {
        public string UserName { get; set; }
    }
}
Run Code Online (Sandbox Code Playgroud)

我想将ContactModel的UserName默认为空字符串.

我已经尝试过NullSubstitute方法,但我认为它试图使用User.Username,而不是仅仅在User属性上.

dav*_*ser 20

您可以编写如下映射代码:

Mapper.CreateMap<Contact, ContactModel>()
            .ForMember( x => x.UserName,  opt => opt.MapFrom( y => (y.User != null) ? y.User.UserName : "" ) );
Run Code Online (Sandbox Code Playgroud)

这将检查是否User为null,然后分配一个emtpy字符串或UserName.

  • 可为空的 DateTime 呢?特性? (2认同)

San*_*zen 6

如果您发现自己在Dave的答案中进行了大量的空检查,那么您可能会考虑应用我之前写过的博客技术:摆脱属性链中的空检查.这将允许你写这个:

Mapper.CreateMap<Contact, ContactModel>()
    .ForMember(x => x.UserName,
        opt => opt.NullSafeMapFrom(y => y.User.UserName) ?? string.Empty);
Run Code Online (Sandbox Code Playgroud)

  • 网址现已关闭。 (2认同)

Jam*_*ory 5

我使用的解决方案是围绕原始委托创建一个闭包,将其包装在 try/catch 块中。Expression.Compile()不幸的是,当原始委托中抛出异常时,有必要使用它来阻止 Visual Studio 捕获异常。可能不建议在高性能环境中使用它,但我在常规 UI 中使用它从未遇到过任何问题。您的里程可能会有所不同。

扩展方法

public static class AutoMapperExtensions
{
    public static void NullSafeMapFrom<T, TResult>(this IMemberConfigurationExpression<T> opt, Expression<Func<T, TResult>> sourceMemberExpression)
    {
        var sourceMember = sourceMemberExpression.Compile();

        opt.MapFrom(src =>
        {
            try
            {
                return sourceMember(src);
            }
            catch (NullReferenceException)
            {}

            return default(TResult);
        });
    }
}
Run Code Online (Sandbox Code Playgroud)

用法

.ForMember(dest => dest.Target, opt => opt.NullSafeMapFrom(src => src.Something.That.Will.Throw));
Run Code Online (Sandbox Code Playgroud)

  • 通过应用缓存机制可以很大程度上减轻由“Expression.Compile()”调用造成的性能损失。但就性能而言,try-catch 是一个更大的问题。但就像你说的,如果只是偶尔调用(与大循环不同),那应该不是问题。 (2认同)