如何映射包括嵌套孩子在内的父类

时间:2018-09-15 13:23:40

标签: c# mapping automapper ienumerable icollection

如果我有两个这样的班级:

1-ParentViewModel:

   public class ParentViewModel
        {
            public Guid Id { get;  set; }
            public string Name { get;  set; }
            public IList<ChildViewModel> Children { get; set; }

        }

2- ChildViewModel

public class ChildViewModel
    {
        public Guid? Id { get; set; }
        public string Name { get; set; }
        public Guid? ParentViewModelId { get;  set; }

    }

我有两个等效的父级域模型: Icollection<Child>代替IList<ChildViewModel>

我想从父视图模型映射到父域(包括子级映射),反之亦然,从域到包含嵌套子项的视图模型?

1 个答案:

答案 0 :(得分:0)

您始终可以手动/繁琐地映射属性,但是,如果需要更通用的解决方案,则可以使用反射来按名称映射属性并处理集合的特殊情况。

*注意: 1.对于属于接口集合类型的属性,这将失败,但是您可以稍微调整代码以处理该问题。 2.未添加错误处理 3.这会尝试按名称映射属性,因此域类和视图模型类必须具有相同的prop名称。 4.它将跳过在目标类上找不到的属性

public class ObjectMapper
{

    public void MapObject(object source, object destination)
    {

        var srcType = source.GetType();//get source type
        var srcProps = srcType.GetProperties();//get src props, supply appropriate binding flags
        var destType = destination.GetType();//get dest type
        var destProps = destType.GetProperties();//get dest props, supply appropriate binding flags

        foreach (var prop in srcProps)
        {
            //find corresponding prop on dest obj
            var destProp = destProps.FirstOrDefault(p => p.Name == prop.Name);
            //only map if found on dest obj
            if (destProp != null)
            {
                //get src value
                var srcVal = prop.GetValue(source);
                //get src prop type
                var propType = prop.PropertyType;
                //get dest prop type
                var destPropType = destProp.PropertyType;

                //special case for collections
                if (typeof(IList).IsAssignableFrom(propType))
                {
                    //instantiate dest collection
                    var newCollection = (IList)Activator.CreateInstance(destPropType);
                    //get source collection
                    var collection = (IList)srcVal;
                    //get dest collection element type
                    var elementType = destPropType.GetGenericArguments().FirstOrDefault();

                    //iterate collection
                    foreach (var element in collection)
                    {
                        //instantiate element type 
                        var tempElement = Activator.CreateInstance(elementType);
                        //call map object on each element
                        MapObject(source: element, destination: tempElement);
                        //add mapped object to new collection
                        newCollection.Add(tempElement);
                    }

                    //set dest object prop to collection
                    destProp.SetValue(destination, newCollection);
                }
                else
                {
                    destProp.SetValue(destination, srcVal);
                }
            }
        }
    }

}