2

Basically I have a method that is passed a list of custom objects. I'm using C#. Each of these contains a name and another list of other custom objects, I'll call these subObjects. These each have a name and a list of strings. I need to loop through all the strings, but keep track of the names of the parent object and subject for error logging purposes. Is there a cleaner, nicer way to do this than nesting foreachs?

foreach (var obj in listOfObjects) 
{
    foreach (var subObj in obj.subObjects)
    {
        foreach (var aString in subObj.strings)
        {
            if (some condition applies) 
            {
                //log error that includes obj, subObj, and subSubObj names, and aString.
            }
        }
    }
}
5
  • What's the condition that you want to use in the if block? Commented Nov 28, 2014 at 18:11
  • 1
    You could use LINQ to do so, but I'm not sure it would be much clearer. Commented Nov 28, 2014 at 18:11
  • 3
    First replace the subobj.strings with subObj.strings) so it compiles. :) I don't see any problem with this structure. It does what it has to. The only problem may be if inside that if you have to exit from the outer foreach, which would require a flag or a beautiful goto. ;) Commented Nov 28, 2014 at 18:12
  • @MarcinJuraszek: how would I do that? Commented Nov 28, 2014 at 18:16
  • 1
    I suggest what @Andrew said. The code makes sense; don't simplify more than you need to. Commented Nov 28, 2014 at 18:24

3 Answers 3

4

You can write a LINQ query to get all error cases

var errors = from obj in listOfObjects
             from subObj in obj.subObjects
             from aString in subObj.strings
             where /* your condition */
             select new { obj, subObj, aString };

and than iterate over them only:

foreach(var errorCase in errors)
{
    // log your error
}

or get the first one:

var error = errors.FirstOrDefault();

depending on your needs.

Sign up to request clarification or add additional context in comments.

3 Comments

I think this is exactly what I was looking for, to me it is much easier to read and deal with. Thanks!
Beware that this solution could be less efficient because of creating new object for each element.
A note on this technique: it also works very effectively if the collections are completely independent (e.g., X/YZ axes), rather than a nested object structure.
0

Adding to MarcinJuraszek answer, if linq to objects is preferred...

var errors = listOfObjects
  .SelectMany(obj => obj.subObjects
    .SelectMany(subObj => subObj.strings
      .Where(r => /* your condition */)
      .Select(aString => new { obj, subObj, aString })));

But there's nothing wrong with the code you posted. Clearly, yours is easier to follow at a quick glance.

1 Comment

That's exactly the same solution, except using different syntax. My code will get transformed by compiler to the same set of method calls, but is clearer and easy to read.
-1

The way I do it :

foreach (YourClass something in YourObject.SelectMany(x => x.Nested).SelectMany(x => x.MoreNesting)) {
    // Do Stuff Here
}

Probably not the best way to do it or whatever, it's just the clearest way for me, while avoiding the triple nesting look I don't quite like.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.