C # как избежать множественного foreach и если заявления

1

У меня есть функция ниже, которая работает и циклически проходит три возможных уровня. Есть ли способ сделать то же самое, что и функция ниже, но не нужно делать несколько инструкций foreach? В основном список reponses может содержать несколько типов GroupResponseTypes, каждый из которых может содержать несколько ElementResponseBaseTypes, которые могут быть самыми разными типами. Я заинтересован в поиске значения в ElementResponseType. И каждый сам ElementResponseBaseType может быть типом GroupResponseType, который содержит несколько типов.

Поэтому я ищу простой способ сканирования всей структуры для определенного элемента Element.Reference и возврата соответствующего значения

Любая помощь высоко ценится

public static string GetValueFromFormField(List<ResponseBaseType> responses, string fieldref)
{
    string fieldvalue = String.Empty;
    foreach (GroupResponseType groups in responses)
    {
        foreach (ElementResponseBaseType firstelements in groups.Responses)
        {
            if (firstelements.GetType() == typeof(ElementResponseType))
            {
                if (firstelements.Element.Reference == fieldref)
                {
                    ElementResponseType firstelement = new ElementResponseType();
                    firstelement = (ElementResponseType)firstelements;
                    fieldvalue = firstelement.Value;
                }
            }
            else if (firstelements.GetType() == typeof(GroupResponseType))
            {
                GroupResponseType secondgroup = new GroupResponseType();
                secondgroup = (GroupResponseType)firstelements;
                foreach (ElementResponseBaseType secondelements in secondgroup.Responses)
                {
                    if (secondelements.GetType() == typeof(ElementResponseType))
                    {
                        if (secondelements.Element.Reference == fieldref)
                        {
                            ElementResponseType secondelement = new ElementResponseType();
                            secondelement = (ElementResponseType)secondelements;
                            fieldvalue = secondelement.Value;
                        }
                    }
                    else if (secondelements.GetType() == typeof(GroupResponseType))
                    {
                        GroupResponseType thirdgroup = new GroupResponseType();
                        thirdgroup = (GroupResponseType)secondelements;
                        foreach (ElementResponseBaseType thirdelements in thirdgroup.Responses)
                        {
                            if (thirdelements.GetType() == typeof(ElementResponseType))
                            {
                                if (thirdelements.Element.Reference == fieldref)
                                {
                                    ElementResponseType thirdelement = new ElementResponseType();
                                    thirdelement = (ElementResponseType)thirdelements;
                                    fieldvalue = thirdelement.Value;
                                }
                            }
                        }
                    }
                }
            }
        }
    }
    return fieldvalue;
}
  • 1
    Вы пытались использовать LINQ для получения более чистого кода фильтрации?
  • 1
    Вы не должны проверять тип каждого объекта и действовать по-другому, вы должны использовать полиморфизм. Каждый из типов должен реализовывать общий метод, основанный на их индивидуальных различиях, позволяя писать код, использующий эти типы, без необходимости знать, каким из производных типов общего интерфейса является конкретный объект.
Показать ещё 6 комментариев
Теги:

2 ответа

1

Вам нужно определить, какие части вашего кода используются повторно, и разложить их на новые методы. Если вы будете делать это снова и снова, в конце концов вы получите что-то вроде этого:

public static string GetValueFromResponses(IEnumerable<ElementResponseBaseType> responses, string fieldref)
{
    foreach (ElementResponseBaseType response in responses)
    {
        ElementResponseType element = response as ElementResponseType;
        if (element != null)
        {
            string foundValue = CheckElement(element, fieldref);
            if (foundValue != null)
            {
                return foundValue;
            }
        }
        else
        {
            GroupResponseType group = response as GroupResponseType;
            if (group != null)
            {
                string foundValue = GetValueFromResponses(group.Responses, fieldref);
                if (foundValue != null)
                {
                    return foundValue;
                }
            }
        }
    }

    return string.Empty;
}

private static string CheckElement(ElementResponseType element, string fieldref)
{
    if (element.Element.Reference == fieldref)
    {
        return element.Value;
    }

    return null;
}

Здесь версия, которая использует Linq (это содержит все функциональные возможности вашего исходного метода):

public static string GetValueFromResponses(IEnumerable<ElementResponseBaseType> responses, string fieldref)
{
    var foundInElements = responses.OfType<ElementResponseType>()
                                   .Select(e => CheckElement(e, fieldref));
    var foundInGroups = responses.OfType<GroupResponseType>()
                                 .Select(g => GetValueFromResponses(g.Responses, 
                                                                    fieldref));

    return foundInElements.Concat(foundInGroups)
                          .FirstOrDefault(s => s != null) ?? string.Empty;
}

private static string CheckElement(ElementResponseType element, string fieldref)
{
    if (element.Element.Reference == fieldref)
    {
        return element.Value;
    }

    return null;
}
  • 0
    Привет, да, эта версия linq - то, что мне было нужно, но не совсем то же самое, хотя моя начальная коллекция - List <ResponseBaseType>, который является только верхним уровнем, и, если какой-либо из них является GroupResponseType, ответы в этом являются ElementResponseBaseTypes ,
  • 0
    Какова ваша иерархия классов? ElementResponseBaseType наследуется от ResponseBaseType или наоборот?
0

Вы должны указать свой базовый тип, в данном случае ResponseBaseType, член, который возвращает все его децидентные листовые узлы. Затем вы можете реализовать поведение этого элемента отдельно для каждого типа. Тип группы может возвращать все листья во всех своих дочерних элементах (рекурсивно), и единственный элемент может возвратиться сам.

Затем вы можете взять любой экземпляр базового типа и получить все листья, или, в данном случае, первый лист. Обратите внимание: поскольку вы только пытаетесь получить первый результат здесь, не все из них, вы бы выиграли от того, чтобы ваша реализация члена группы использовала отложенное выполнение, так что вам не нужно беспокоиться о вычислении всех значений просто чтобы получить первый.

Как бы сложно это ни казалось, сначала требуется очень мало кода для реализации.

public abstract class ResponseBaseType
{
    public abstract IEnumerable<ElementResponseType> Leaves { get; }
}

public class GroupResponseType : ResponseBaseType
{
    public IEnumerable<ResponseBaseType> Children { get; private set; }
    public override IEnumerable<ElementResponseType> Leaves
    {
        get
        {
            return Children.SelectMany(child => child.Leaves);
        }
    }
}

public class ElementResponseType : ResponseBaseType
{
    public override IEnumerable<ElementResponseType> Leaves
    {
        get
        {
            yield return this;
        }
    }
}

Это позволяет вам отображать список ответов, сопоставлять их с последовательностями всех их листьев, а затем получать из этого первый/последний лист.

responses.SelectMany(response => response.Leaves).Last();

Ещё вопросы

Сообщество Overcoder
Наверх
Меню