servicestack,C#,Asp.net,servicestack" /> servicestack,C#,Asp.net,servicestack" />

C# 如何将.NET函数调用自动映射到属性?

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() {

编辑:这最初是针对1:1映射的,但我发现我需要一个更复杂的递归映射,所以在这里发布了一个新问题:

我尝试使用ServiceStack ConvertTo方法将实体类函数一般映射到视图模型。这映射了所有相似的类型和属性名,效果很好,但我想找到一种方法将函数的结果映射到属性。这里有一些代码

实体示例:

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