在映射定义中的潜在null属性上调用扩展方法

时间:2014-12-03 19:39:15

标签: c# asp.net-mvc-5 automapper

鉴于以下内容:

public class Foo
{
    public int ID {get;set;}
    public Bar Bar {get;set;}
}

public class Bar
{
    public int ID { get; set; }
    public string Name { get; set; }
}

public class FooDetailsViewModel
{
    public int ID { get; set; }
    public string Bar { get; set; }
}

我希望能够在映射中调用以下扩展方法:

public static string ToNoneString(this string s)
    {
        if (String.IsNullOrEmpty(s))
        {
            return "None";
        }
        else
        {
            return s;
        }
    }

问题是Foo的Bar属性可能为null,因此以下原因并不明显:

Mapper.CreateMap<Foo, FooDetailsViewModel>().ForMember(dest => dest.Bar, opts => opts.MapFrom(src => src.Bar.Name.ToNoneString()));

我知道我可以在映射后调用我的控制器中的扩展方法,但我希望在创建映射时能以某种方式执行此操作。

2 个答案:

答案 0 :(得分:1)

您可以在ForMember调用中使用简单的条件语句:

Mapper.CreateMap<Foo, FooDetailsViewModel>()
    .ForMember(
        dest => dest.Bar,
        opts => opts.MapFrom(
           src => src.Bar != null ? src.Bar.Name.ToNoneString() : null));

您还可以将扩展方法移至Bar类:

public static string ToNoneString(this Bar bar)
{
    if (bar != null && !string.IsNullOrEmpty(bar.Name))
    {
        return bar.Name;
    }
    else 
    {
        return "None";
    }
}

然后更新您的映射:

Mapper.CreateMap<Foo, FooDetailsViewModel>()
    .ForMember(
        dest => dest.Bar,
        opts => opts.MapFrom(src => src.Bar.ToNoneString()));

答案 1 :(得分:1)

您可以创建IfNotNull扩展名方法:

static TResult IfNotNull<TSource, TResult>(
    this TSource instance,
    Func<TSource, TResult> getter,
    TResult defaultValue = default(TResult))
        where TSource : class
{
    return instance != null ? getter(instance) : defaultValue;
}

并像这样使用它:

Mapper.CreateMap<Foo, FooDetailsViewModel>()
      .ForMember(
          dest => dest.Bar,
          opts => opts.MapFrom(
                         src => src.Bar.IfNotNull(_ => _.Name).ToNoneString()));

IfNotNull基本上是C#6空传播运算符的原始等价物,它允许你这样做:

Mapper.CreateMap<Foo, FooDetailsViewModel>()
      .ForMember(
          dest => dest.Bar,
          opts => opts.MapFrom(
                         src => (src.Bar?.Name).ToNoneString()));