2014-12-03 152 views
0

考慮以下幾點:調用擴展方法

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屬性可能爲空,因此下列不起作用的原因很明顯:

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

我知道我可以在映射後在我的控制器中調用擴展方法,但我希望在創建映射時可以以某種方式執行此操作。

+0

是否有可能將構造邏輯添加到'Foo'中,以默認的'new Bar(){ID = -1,Name = String.Empty}來初始化它,所以它不是null?您當然必須稍後再驗證,但是這會阻止空引用 – Marco 2014-12-03 19:43:53

回答

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())); 
+0

即使Bar屬性爲null,我也希望我的視圖模型的Bar屬性顯示爲「None」。 – 2014-12-03 19:45:32

+1

@MattyM:啊,抱歉 - 我會更新我的答案。顯而易見的選擇是將''None'放在條件的「else」部分中。 – 2014-12-03 19:46:29

+0

哇。我不能相信我錯過了這一點。謝謝! – 2014-12-03 19:53:24

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())); 
+1

在C#6中,也許你會需要一個圓括號,src =>(src.Bar?.Name).ToNoneString()'。否則,我的理解是''.''會阻止下一個'.'被「擊中」。即使最後一個'.'調用了擴展方法(不是實例方法),我也會認爲這是真的。有人可以訪問C#6編譯器評論嗎? – 2014-12-03 22:42:19

+1

@JeppeStigNielsen,每個人都可以訪問C#6編譯器,你只需要安裝它;)。我有一個VS2015的Azure虛擬機,我會試一試 – 2014-12-03 23:21:22

+1

@JeppeStigNielsen,是的,你是對的......我會修復我的答案 – 2014-12-03 23:38:29