0

I need to retrieve all objects of type X from a complex object.

public class Dog
{
    public string Name {get;set;}
    public int Age {get;set;}
    public Owner Owner{get;set;}
    public Kennel Kennel {get;set;}
}

public class Kennel
{
    public string Name {get;set;}
    public Address Address{get;set;}
    public List<Dog> Dogs {get;set;}
}

public class Owner
{
    public string Name {get;set;}
    public string State {get;set;}
    public Address Address{get;set;}
}

If I have an object composed of Dog, I would need to retrieve all address objects in all child objects.

Heretic Monkey
  • 11,687
  • 7
  • 53
  • 122
AnxiousdeV
  • 373
  • 1
  • 3
  • 20

3 Answers3

1

You don't need recursion here. Just SelectMany

Kennel home = getKennel();

List<Address> AllOwnerAddresses = home.Dogs.SelectMany(d = > d.Owner.Address).ToList();
Travis J
  • 81,153
  • 41
  • 202
  • 273
1

If I understand you correctly, you might need to use Reflection to retrieve the Address objects:

public static class MyExtensions
{
    public static List<Address> GetAddresses(this Dog dog)
    {
        var addresses = new List<Address>();
        GetAddress(dog, ref addresses);
        return addresses;
    }

    private static void GetAddress(object property, ref List<Address> addresses)
    {
        if (property == null)
        {
            return;
        }

        var props = property.GetType()
                            .GetProperties()
                            .Where(p => p.PropertyType.IsClass && 
                                       !p.PropertyType.IsPrimitive)
                            .ToList();

        foreach (var prop in props)
        {
            if (prop.PropertyType == typeof(Address))
            {
                var address = prop.GetValue(property) as Address;
                addresses?.Add(address);
            }

            var next = prop.GetValue(obj: property);

            // When property is a collection
            if (next is IEnumerable collection)
            {
                foreach (var item in collection)
                {
                    GetAddress(property: item,
                               addresses: ref addresses);
                }
            }
            else
            {
                GetAddress(property: next,
                           addresses: ref addresses);
            }
        }
    }
}

And usage example:

var dogs = new List<Dog>();
for (int i = 0; i < 5; i++)
{
    var dog = new Dog
    {
        Name = $"Dog - {i}",
        Age = 10,
        Kennel = new Kennel
        {
            Address = new Address()
        },
        Kennels = new List<Kennel>
        {
            new Kennel
            {
                Address = new Address()
            },
            new Kennel
            {
                Address = new Address()
            },
            new Kennel()
            {
                Address = new Address()
            }
        },
        Owner = new Owner
        {
            Address = new Address(),
            Kennel = new Kennel
            {
                Address = new Address()
            }
        }
    };

    dogs.Add(dog);
}

var address = dogs.Select(dog => dog.GetAddresses());
Console.WriteLine(address.Sum(a => a.Count)); // will print 30

Please note that using Reflection could affect the performance of your application.

Arsen Khachaturyan
  • 7,904
  • 4
  • 42
  • 42
0

Assuming that the structure is a tree

static IEnumerable<Address> GetAddresses(Dog dog)
{ 
    yield return dog.Owner.Address;
    yield return dog.Kennel.Address;
    foreach (var addr in dog.Kennel.Dogs.SelectMany(dogC => GetAddresses(dogC)))
    {
        yield return addr;
    }
}
Lesiak
  • 22,088
  • 2
  • 41
  • 65