可以简化泛型类吗?

时间:2011-10-23 16:13:36

标签: c# generics automapper

同事 在我们的项目中,我们使用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);

但是:如果Locations不包含元素或者为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 个答案:

答案 0 :(得分: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;
}

然后结果将是这样的:     选择=&GT; opt.FromMap(S =&GT; s.Locations.NullToEmpty()选择(LOC =&GT; loc.Address).FirstOrDefault());