C# 如何将.NET函数调用自动映射到属性?
编辑:这最初是针对1:1映射的,但我发现我需要一个更复杂的递归映射,所以在这里发布了一个新问题: 我尝试使用ServiceStack ConvertTo方法将实体类函数一般映射到视图模型。这映射了所有相似的类型和属性名,效果很好,但我想找到一种方法将函数的结果映射到属性。这里有一些代码 实体示例:C# 如何将.NET函数调用自动映射到属性?,c#,asp.net,servicestack,C#,Asp.net,servicestack,编辑:这最初是针对1:1映射的,但我发现我需要一个更复杂的递归映射,所以在这里发布了一个新问题: 我尝试使用ServiceStack ConvertTo方法将实体类函数一般映射到视图模型。这映射了所有相似的类型和属性名,效果很好,但我想找到一种方法将函数的结果映射到属性。这里有一些代码 实体示例: public class Item { public long Id {get; set;} public List<Product> GetProducts() {
public class Item {
public long Id {get; set;}
public List<Product> GetProducts() {
return Repository.GetAll<Product>();
}
}
公共类项目{
公共长Id{get;set;}
公共列表产品(){
返回Repository.GetAll();
}
}
ViewModel示例:
public class ItemViewModel {
public long Id {get;set;}
public List<Product> Products {get; set;}
}
公共类ItemViewModel{
公共长Id{get;set;}
公共列表产品{get;set;}
}
理想的结果是有一个映射函数,它在实体类中查找与返回类型匹配的方法,函数名为“Get”+Property name,然后执行它并将结果映射到视图模型。虽然您可能会发现类似于或可能已经包含此功能,没有什么能阻止您编写一个快速实用的小方法:
public TTarget MapToViewModel<TSource, TTarget>(TSource source)
where TTarget : new()
{
var sourceType = source.GetType();
var targetProperties = typeof(TTarget).GetProperties(BindingFlags.Public | BindingFlags.Instance);
var sourceProperties = sourceType.GetProperties(BindingFlags.Public | BindingFlags.Instance);
var sourceMethods = sourceType.GetMethods(BindingFlags.Public | BindingFlags.Instance);
var target = Activator.CreateInstance<TTarget>();
foreach (var prop in targetProperties)
{
var sourceProp = sourceProperties.FirstOrDefault(x => x.Name == prop.Name);
if (sourceProp != null)
{
prop.SetValue(target, sourceProp.GetValue(source, null), null);
}
else
{
var sourceMethod = sourceMethods.FirstOrDefault(x => x.Name == "Get" + prop.Name);
if (sourceMethod != null)
{
prop.SetValue(target, sourceMethod.Invoke(source, null), null);
}
}
}
return target;
}
如果在常规模型中有任何方法参数,请小心。如果您发现您的模型太复杂(或者没有遵循一个或两个命名约定),那么您最好使用AutoMapper之类的工具。但是,对于简单的映射,类似这样的东西应该可以完成这项工作。使用ServiceStack进行这种映射将很难形成一个通用的解决方案,因为您基本上必须编写代码来匹配
产品
到GetProducts
您可以使用另一个映射库,如,它自动使用GetX()
来填充X
// one time config
Mapper.CreateMap<Item, ItemViewModel>();
Mapper.AssertConfigurationIsValid();
// whenever you map
Item item = // whatever
ItemViewModel viewModel = Mapper.Map<ItemViewModel>(item);
// viewModel.Products is populated from item.GetProducts()
看起来AutoMapper是一个更加健壮的映射器。即使使用Service ESTACK做其他的部分,使用AutoPuxor进行映射也是值得的。尼斯,我想AutoAppER可以做一些类似的事情(即使只是使用<代码>后缀< /COD>函数),我没有考虑AutoPAPER。Automapper会递归地支持这一点吗?是的(我想;不确定“递归地”是什么意思),例如,如果
Products
和GetProducts
返回了不同的类型,但在这两种产品类型之间创建了一个映射,(例如Mapper.CreateMap();
)它也会自动映射这些项目。添加了一个附带问题,因为我认为Automapper将能够更轻松地完成我想要的任务。谢谢,我把它弄好了。现在我有另一个难题。要使这个递归有多困难?例如,如果Product类有一个属性列表Images,我需要从Product类调用GetImages(),我不知道这需要递归调用。您的意思是,如果对象上同时存在方法和属性,则需要调用该方法吗?如果是这种情况,您可以切换属性和方法的If
语句以首先检查方法。不完全是,我的意思是,如果映射的对象有另一个属性需要通过调用不同的函数来映射。你的回答帮助我决定我需要更复杂一点的东西,似乎Automapper可以处理。我在这里问了另一个问题是的,有了AutoMapper,你可以为多个对象设置地图,并在途中发送。例如,您可以调用Mapper.CreateMap()
和Mapper.CreateMap()
。然后,当您调用Mapper.Map(product)
时,它应该返回您需要的内容。
// one time config
Mapper.CreateMap<Item, ItemViewModel>();
Mapper.AssertConfigurationIsValid();
// whenever you map
Item item = // whatever
ItemViewModel viewModel = Mapper.Map<ItemViewModel>(item);
// viewModel.Products is populated from item.GetProducts()
Mapper.CreateMap<Item, ItemViewModel>()
.ForMember(dest => dest.Products,
opt => opt.ResolveUsing(src => src.GetProducts()));