2011-10-23 104 views
1

同事, 在我们的项目中,我们使用AutoMapper来映射模型。可以简化泛型类吗?

我们有一个模型:

public class Location 
{ 
    public string Address { get; set; } 
} 

public class Person 
{ 
    public string Name { get; set;} 
    public Collection<Location> Locations { get; set; } 
} 

我们也有一个视图模型:

public class PersonView 
{ 
    public string Name { get; set; } 
    public string Location { get; set;} 
} 

到模型映射到视图模型中,我们可以定义类似以下内容:

Mapper.CreateMap<Person, PersonView>(d=>d.Name, opt=>opt.FromMap(s=>s.Name); 
Mapper.CreateMap<Person, PersonView>(d=>d.Address, opt=>opt.FromMap(s=>s.Locations.First().Address); 

但是:如果位置不包含元素或为null,那么我们将得到一个异常。

来自对岸,我们可以定义一个函数来获取一个值:

Mapper.CreateMap<Person, PersonView>(d=>d.Address, opt=>opt.FromMap(s=> 
{ 
    var item = s.Locations.FirstOrDefault(); 
    if(item == null) 
    { 
     return string.Empty; 
    } 

    return item.Address; 
}); 

这个表达式难以阅读。我尝试创建一个IValueResolver来简化映射。

public class CollectionItemResolver<TSource, TSourceItem, TResult> 
    where TSource : class 
    where TSourceItem : class 
{ 
    private readonly Func<TSource, IEnumerable<TSourceItem>> _sourceSelector; 
    private readonly Func<TSourceItem, TResult> _selector; 
    private readonly TResult _defaultValue; 

    public CollectionItemResolver(Func<TSource, IEnumerable<TSourceItem>> source, Func<TSourceItem, TResult> selector) 
     : this(source, selector, default(TResult)) 
    { 
    } 

    public CollectionItemResolver(Func<TSource, IEnumerable<TSourceItem>> source, Func<TSourceItem, TResult> selector, TResult defaultValue) 
    { 
     _sourceSelector = source; 
     _selector = selector; 
     _defaultValue = defaultValue; 
    } 

    public TResult Resolve(TSource source) 
    { 
     var items = _sourceSelector(source); 

     if (items == null) 
     { 
      return _defaultValue; 
     } 

     var item = items.FirstOrDefault(); 
     if (item == null) 
     { 
      return _defaultValue; 
     } 

     var value = _selector(item); 
     return value; 
    } 
} 

然后使用这样的事情:

Mapper.CreateMap<Person, PersonView>(d=>d.Address, opt=>opt.ResolveUsing(
    new CollectionItemResolver<Person, Location, string>(p=>p.Locations, i=>i.Address))); 

可以简化通用解析器? 例如,不要定义嵌套项目的类型?

new CollectionItemResolver<Person, string>(p=>p.Locations, i=>i.Address))); 

感谢,

+1

'Gents'?那些女士们读你的问题呢? –

+0

@DarinDimitrov - +1表情直白地说出来。 – Steve

+0

我会回到表达。这对我来说更容易阅读。 – Enigmativity

回答

1

如何:

Mapper.CreateMap<Person, PersonView>(d=>d.Address, opt=>opt.FromMap(s=>s.Locations.Select(loc=>loc.Address).FirstOrDefault()); 

购买的方式,Automapper知道如何Null转换为string.Empty

PS,希望对你有收集Locations始终不为空。 但如果没有,那么我建议使用此extension

public static IEnumerable<TSource> NullToEmpty<TSource>(
    this IEnumerable<TSource> source) 
{ 
    if (source == null) 
     return Enumerable.Empty<TSource>(); 

    return source; 
} 

那么结果会是这样的:。 选择=> opt.FromMap(S => s.Locations.NullToEmpty()选择(LOC = > loc.Address).FirstOrDefault());

相关问题