Iterate through dynamic levels I have the below function that works and cycles through 3 possible levels. Is there a way to do the same as the function below but not have to do the multiple foreach statements, and not have to specify the number of levels as it is dynamic?

Basically the responses list can contain multiple GroupResponseTypes each of these can contain multiple ElementResponseBaseTypes which can be a variety of types themselves I'm interested in finding a value in an ElementResponseType And each ElementResponseBaseType itself can be a GroupResponseType, it to containing multiple types.

I'm looking at an easy way to scan through the whole structure for a specific Element.Reference and return the relevant value.

public static string GetValueFromFormField(List&lt;ResponseBaseType&gt; 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;
    }
You are using Conditional, and i would recommend replacing these with Visitor.

See Replace Conditional with Visitor article by Martin Fowler.

The generic visitor pattern in the code snippet belo is useful for all kind of added operation types on the hierrarchy:

using System.Collections.Generic;
using System.Linq;
using NUnit.Framework;

namespace Traversal.Tests
{
    class VisitorTests
    {
        [Test]
        public void TestThis()
        {
            var topLevelResponse = new GroupResponse(
                new Response[]
                {
                    new ElementResponse("foo value", "foo"),
                    new GroupResponse(new[]
                        {
                            new ElementResponse("bar value", "bar")
                        })
                });

            var actualElement =
                topLevelResponse.Accept(new TraverseElementsVisitor()).FirstOrDefault(el =&gt; el.Reference == "bar");

            Assert.IsNotNull(actualElement);

            Assert.AreEqual("bar value", actualElement.Value);
        }
    }


    public interface IResponseVisitor&lt;T&gt;
    {
        T Visit(ElementResponse elementResponse);
        T Visit(GroupResponse groupResponse);
    }

    public abstract class Response
    {
        public abstract T Accept&lt;T&gt;(IResponseVisitor&lt;T&gt; visitor);
    }

    public class ElementResponse : Response
    {
        public ElementResponse(string value, string reference)
        {
            Reference = reference;
            Value = value;
        }

        public string Value { get; private set; }
        public string Reference { get; private set; }

        public override T Accept&lt;T&gt;(IResponseVisitor&lt;T&gt; visitor)
        {
            return visitor.Visit(this);
        }
    }

    public class GroupResponse : Response
    {
        public GroupResponse(IEnumerable&lt;Response&gt; responses)
        {
            Responses = responses;
        }

        public IEnumerable&lt;Response&gt; Responses { get; private set; }

        public override T Accept&lt;T&gt;(IResponseVisitor&lt;T&gt; visitor)
        {
            return visitor.Visit(this);
        }
    }

    public class TraverseElementsVisitor : IResponseVisitor&lt;IEnumerable&lt;ElementResponse&gt;&gt;
    {
        public IEnumerable&lt;ElementResponse&gt; Visit(ElementResponse elementResponse)
        {
            yield return elementResponse;
        }

        public IEnumerable&lt;ElementResponse&gt; Visit(GroupResponse groupResponse)
        {
            return groupResponse.Responses.SelectMany(r =&gt; r.Accept(this));
        }
    }
}


Your class hierarchy is not obvious to me, not sure i completely understand the class hierarchy you are using, so in the code example i provided a simplified one.

I'd say *Type postfix is redundant in this case, because you are using the objects to represent objects of a type, not the types themselves. Compare to usage of class name in System.Type, instances of which actually represent types.

Looks like you are putting same responsibility to multiple classes. Try to cleanly separate what is what, and what is common.