是否可以简化泛型类?
同事, 在我们的项目中,我们使用 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)));
Is possible simple generic rever? 例如不定义嵌套项的类型?
new CollectionItemResolver<Person, string>(p=>p.Locations, i=>i.Address)));
谢谢,
Colleagues,
In our project we are using AutoMapper to map models.
We have a model:
public class Location
{
public string Address { get; set; }
}
public class Person
{
public string Name { get; set;}
public Collection<Location> Locations { get; set; }
}
also we have a view model:
public class PersonView
{
public string Name { get; set; }
public string Location { get; set;}
}
To mapping a model to a view model we may define something like the following:
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);
BUT: If Locations will not contains elements or is null then we will get an exception.
From other side, we may define a function to get a value:
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;
});
This expressions hard to read. And I try create a IValueResolver for simplify mapping.
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;
}
}
And then use something like this:
Mapper.CreateMap<Person, PersonView>(d=>d.Address, opt=>opt.ResolveUsing(
new CollectionItemResolver<Person, Location, string>(p=>p.Locations, i=>i.Address)));
Is possible simplify generic resolver?
For instance do not define the type of nested item?
new CollectionItemResolver<Person, string>(p=>p.Locations, i=>i.Address)));
Thanks,
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
这个怎么样:
买个方式,
Automapper
知道如何将Null
转换为string.Empty
PS,希望你有收藏
Locations< /code> 始终不为空。
但如果没有,那么我建议使用这个 扩展:
那么结果将是这样的:
opt=>opt.FromMap(s=>s.Locations.NullToEmpty().Select(loc=>loc.Address).FirstOrDefault());
How about this:
Buy the way,
Automapper
knows how to convertNull
tostring.Empty
PS, hope you have collection
Locations
always not null.But if not, then I suggest use this extension:
Then result will be something like this:
opt=>opt.FromMap(s=>s.Locations.NullToEmpty().Select(loc=>loc.Address).FirstOrDefault());