基于属性值从嵌套对象中提取对象并将项目投影到新类

时间:2018-05-21 22:46:28

标签: c# linq mapping automapper

我有以下嵌套输入类

 //InputClass
public class MessageViewModel 
{
    public bool IsSelected { get; set; }

    public string Subject { get; set; }

    public DateTime CreationDate { get; set; }
    public List<MessageViewModel> Messages { get; set; }
}

我想创建以下类型的新实例:

 //Target Class
public class DestinationClass
{
    public string Subject { get; set; }
}

对于具有属性IsSelected = true的每个实例MessageViewModel 在这种情况下,最佳解决方案是什么?这可以使用AutoMapper来实现吗?

编辑:

假设我有以下对象:

var vm = new MessageViewModel
        {
            Messages = new List<MessageViewModel> {
                            new MessageViewModel {
                                IsSelected = true,
                                    Messages = new List<MessageViewModel> {
                                            new MessageViewModel { IsSelected = true,
                                                                    Messages = new List<MessageViewModel> { new MessageViewModel { },
                                                                                                            new MessageViewModel { },
                                                                        new MessageViewModel { } } } } } }
        };

我想遍历它,只提取并映射IsSelected等于true的MessageViewModels。

求助:

使用以下代码:

 public static class TraversalHelper
{
    public static void TraverseAndExecute<T>(this T composite, Func<T, IEnumerable<T>> selectChildren, Action<T> action)
        where T : class
    {
        action.Invoke(composite);
        composite.TraverseAndExecute(selectChildren, action, new List<T> { composite });
    }

    private static void TraverseAndExecute<T>(this T composite, Func<T, IEnumerable<T>> selectChildren, Action<T> action, IList<T> invokedComponents)
        where T : class
    {
        invokedComponents = invokedComponents ?? new List<T>();
        var components = selectChildren(composite) ?? new T[] { };
        foreach (var component in components)
        {
            if (!invokedComponents.Contains(component))
            {
                action.Invoke(component);
                invokedComponents.Add(component);
                component.TraverseAndExecute(selectChildren, action, invokedComponents);
            }
            else
            {

            }
        }
    }
}

我设法迭代了我的分层对象:

 var vm = new MessageViewModel
        {
            Messages = new List<MessageViewModel> {
                            new MessageViewModel {
                                IsSelected = true,
                                    Messages = new List<MessageViewModel> {
                                            new MessageViewModel {
                                                IsSelected = true,
                                                Messages = new List<MessageViewModel> {
                                                    new MessageViewModel { },
                                                    new MessageViewModel { },
                                                    new MessageViewModel { } } } } } }
        };

        var results = new List<DestinationClass>();

        vm.TraverseAndExecute(_ => _.Messages, _ => {
            if(_.IsSelected == true)
            {
                results.Add(new DestinationClass { Subject = _.Subject });
            }
        });

2 个答案:

答案 0 :(得分:2)

由于您的类是嵌套层次结构,因此您需要一个扩展方法。

具有更多LINQ特征的一个将是:

public static IEnumerable<T> Flatten<T>(this T current, Func<T, IEnumerable<T>> childrenFn) {
    var working = new Stack<T>();
    working.Push(current);

    while (working.Count > 0) {
        current = working.Pop();
        yield return current;

        if (childrenFn(current) != null)
            foreach (var child in childrenFn(current))
                working.Push(child);
    }
}

这将获取一个父对象和一个从父对象返回子对象列表的函数,并返回所有被展平的对象。

现在您可以使用它来产生答案:

var ans = vm.Flatten(mvm => mvm.Messages)
            .Where(mvm => mvm.IsSelected)
            .Select(mvm => new DestinationClass() { Subject = mvm.Subject });

答案 1 :(得分:0)

在这种情况下,我将使用IEnumerable的Message ViewModel作为DestinationClass中的构造函数参数。然后,您可以使用System.Linq迭代MessageViewModels集合,并选择条件为true的每个模型,并将其转换为IEnumerable of DestinationClass。

这只是解决此问题的一种方法。如果您可以向我们提供有关您的解决方案架构的更多详细信息,我们将更容易为您提供支持。问候EnvyIT